Синхронизировать потоки с мьютексом - PullRequest
0 голосов
/ 25 сентября 2018

Я работаю над назначением, которое требует от меня: 1. Открыть файл и прочитать из него в одном потоке, 2. Поскольку каждое значение читается одно за другим, сохранить каждое значение в глобальной переменной, а затем инициировать мьютекс, так что 3Второй поток может использовать эту глобальную переменную, чтобы записать ее в файл, прежде чем поток 1 прочитает следующее значение, и процесс повторится.У меня возникают проблемы с синхронизацией моего мьютекса, чтобы после прочтения значения оно могло быть записано вторым потоком.В настоящее время поток 2 выводит только 0 и не проходит через него.Я не уверен, что я делаю неправильно.Я имею в виду, что когда я блокирую поток, он быстро повторяется перед переходом к потоку 2. Вот мой исходный код:

#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);
}

РЕДАКТИРОВАТЬ: будет ли правильный способ сделать это для потока 2 такжевызовите inputThread и в цикле while заблокируйте мьютекс, а после цикла while напишите другой оператор для записи в файл и закройте мьютекс после этого?Как я должен сделать обе операции в рамках одной и той же функции?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Мьютекс обеспечивает слияние MUT ual EX среди набора потоков.Общая идея заключается в том, что каждый поток блокирует (один и тот же) мьютекс перед выполнением действий, во время которых все остальные должны быть исключены из работы, а затем разблокирует его по завершении.Только один поток может удерживать мьютекс заблокированным за один раз, поэтому возникает исключение.

Кроме того, мьютексы обеспечивают семантику барьера памяти, так что запись в память, выполняемая любым потоком до освобождения мьютекса, гарантированно будет виднакаждым другим потоком после того, как он блокирует мьютекс.Это не гарантируется, если не использовать мьютекс или какой-либо другой объект синхронизации.

Вам нужны оба этих свойства.Вам нужен писатель, чтобы увидеть значение, прочитанное читателем, и вам нужно подождать, пока читатель прочитает каждое значение, прежде чем он попытается записать его.Также необходимо, чтобы читатель ждал после каждого чтения, пока писатель не записал прочитанное значение, чтобы не заменить его новым, прежде чем писатель сможет написать его.Таким образом, каждый поток должен обращаться к переменной value только при удержании мьютекса заблокированным, но, кроме того, должен разблокировать мьютекс после каждого доступа, чтобы позволить другому потоку продолжить.

К сожалению, один мьютекс не являетсяэтого достаточно, чтобы решить вашу проблему. Они могут помешать вашим потокам работать одновременно, но сами по себе они не могут заставить ваши потоки чередоваться, что вам и нужно.Мьютексы обычно объединяются с другим типом объекта синхронизации, «условной переменной», чтобы обеспечить выполнение каждого потока тогда и только тогда, когда это предполагается сделать.CV, как обычно используется там, как обычно, хедлайнер, но его нужно использовать вместе с мьютексом.

Здесь вы можете найти много ответов на SO и множество веб-уроков о том, как использовать мьютексы и резюме для созданиятемы по очереди правильно.Вы можете попробовать Googling как «производитель-потребитель», так как это общее название для категории проблемы, которую вы пытаетесь решить.Вберите «мьютекс» и «переменную условия» в условия поиска, и вы должны ударить золото в верхнем ряду хитов.

0 голосов
/ 25 сентября 2018

Вы хотите заблокировать мьютекс, прежде чем делать что-либо с переменной, которую вы пытаетесь защитить. Это включает в себя вашу функцию подсчета.

У меня сейчас нет среды Linux, но что-то вроде этого должновы попадете на правильный путь.

Как сказал комментатор, вам также необходимо использовать цикл в вашей функции подсчета.В противном случае вы получите только одно значение.То, как вы управляете циклом, будет зависеть от того, как именно вы хотите, чтобы данные передавались.Вполне возможно, вам понадобится второй мьютекс для этого.

Опять же, имейте в виду, что вы хотите заблокировать мьютекс, прежде чем делать что-либо с вашей защищенной переменной в любом месте, к которому у вас есть доступ.Даже чтение его без блокировки приведет к поведению, которое не гарантированно будет точным.

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);
}

Дайте мне знать, если у вас есть какие-либо проблемы с этим.

Похоже, что это назначение может бытьпытаясь представить проблему производителя-потребителя.Я думаю, что дальнейшее чтение поможет вам в будущем.

Перечитав ваш ответ, я думаю, что именно проблема производителя и потребителя - именно то, что вы хотите сделать.Если вы сделаете это, как вы упомянули в редактировании, то реализация в основном однопоточная.Это на самом деле не научит вас тому, к чему, как мне кажется, урок пытается добраться.

Некоторые вещи, которые будут полезны для знания

  • Круговые буферы
  • Проблема производителя-потребителя
  • Обучение тому, как избежать тупика с несколькими мьютексами
...