简体   繁体   中英

Synchronize pthreads with mutex

I am working on an assignment which requires me to 1. Open a file and read from it in one thread, 2. As each value is read one by one save each value to a global variable and then initiate a mutex so 3. The second thread can use that global variable write it to a file before the next value is read by thread 1 and the process repeats. I am having trouble timing up my mutex so that once a value is read it can be written by the second thread. Presently, thread 2 only prints out 0 and it isn't iterating through. I am not sure what I am doing wrong. What I am thinking is that when I lock the thread it is rapidly iterating before going to thread 2. Here is my source code:

#include <stdio.h>
#include <stdio.h>
#include <pthread.h>

int value;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *inputThread(void * args) {
  FILE *input = fopen("hw4.in", "r");
  while(!feof(input)) {
    //printf("Thread locked.\n");
    fscanf(input, "%d\n", &value);
    pthread_mutex_lock(&mutex);
    printf("value: %d\n", value);
    //printf("Thread unlocked.\n");
    pthread_mutex_unlock(&mutex);
  }
  fclose(input);
  pthread_exit(NULL);
}

void *counting(void *args) {
  printf("Value: %d\n", value);
  pthread_exit(NULL);
}

int main() {

  //Creating thread1
  pthread_t pt1;
  pthread_create(&pt1, NULL, inputThread, NULL);

  //Creating thread2
  pthread_t pt2;
  pthread_create(&pt2, NULL, counting, NULL);

  //Joining thread1
  pthread_join(pt1, NULL);
  pthread_join(pt2, NULL);
}

EDIT: Would the proper way to do this be for thread2 to also call inputThread and in the while loop lock the mutex and after the while loop write another statement to write to the file and close the mutex after that? As in I have to do both operations within the same function?

A mutex provides MUT ual EX clusion among a set of threads. The general idea is that each thread locks the (same) mutex before performing actions during which all the others must be excluded from running, and then unlocks it when done. Only one thread can hold the mutex locked at a time, so thereby comes the exclusion.

Additionally, mutexes provide memory barrier semantics such that writes to memory performed by any thread prior to releasing the mutex are guaranteed to be seen by each other thread after it locks the mutex. That is not guaranteed to be the case without use of a mutex or some other variety of synchronization object.

You need both of those properties. You need the writer to see the value read by the reader, and you need it to wait for the reader to read each value before it tries to write it. You also need the reader to wait after each read until the writer has written the value read, so as not to replace it with a new one before the writer has a chance to write it. Thus, each thread must access variable value only while holding the mutex locked, but must furthermore unlock the mutex after each access to allow the other thread to proceed.

Unfortunately, a mutex alone is not enough to solve your problem. They can prevent your threads from running at the same time, but they cannot, by themselves, make your threads alternate, which is what you need. Mutexes are normally combined with another kind of synchronization object, a "condition variable", to provide for each thread to run when, and only when, it is supposed to do. The CV, used properly, as usually the headliner there, but it needs to be used together with a mutex.

You can find many answers here on SO and many web tutorials for how to use mutexes and CVs to make threads take turns properly. You might try Googling for "producer consumer", as that is a common name for the category of problem you are trying to solve. Throw "mutex" and "condition variable" into the search terms and you should strike gold within the top handful of hits.

You want to lock the mutex before doing anything with the variable you are trying to protect, This includes your counting function.

I don't have a Linux environment available right now, but something like this should get you on the right track.

Like the commenter said, you also need to use a loop in your counting function. Otherwise, you will only get one value read out. How you control the loop will depend on exactly how you want the data to flow. It is very possible you will need a second mutex for this.

So again, keep in mind that you want to lock the mutex before doing anything with your protected variable in any place that you access it. Even reading it without a lock will cause behavior that is not guaranteed to be accurate.

void *inputThread(void * args) {
  FILE *input = fopen("hw4.in", "r");
  while(!feof(input)) {
    //printf("Thread locked.\n");
    /*-------- Right below here you acces value by trying to insert input to it 
               using fscanf(input, "%d\n", &value)
               so you need to lock the mutext before doing that */
    pthread_mutex_lock(&mutex);        
    fscanf(input, "%d\n", &value);
    printf("value: %d\n", value);
    //printf("Thread unlocked.\n");
    pthread_mutex_unlock(&mutex);
  }
  fclose(input);
  pthread_exit(NULL);
}

void *counting(void *args) {
  while(some_condition) {
      // you also try to access value in this method so you need to use the mutex
     pthread_mutex_lock(&mutex);
     printf("Value: %d\n", value);
     pthread_mutex_unlock(&mutex);
  } // End while(some_condition)
  pthread_exit(NULL);
}

Let me know if you have any issues with this.

This assignment seems like it could be trying to introduce the producer-consumer problem. I think reading more into that would help you in the future.

After re-reading your answer, I think looking at the producer-consumer problem is exactly what you want to do. If you do it as you mention in the edit, then the implementation is basically single threaded. That wouldn't really teach you what I think the lesson is trying to get at.

Some things that will be helpful knowledge

  • Circular Buffers
  • Producer-Consumer Problem
  • Learning how to avoid deadlock with multiple mutexes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM