将pthread与互斥锁同步

时间:2018-09-25 00:46:32

标签: c pthreads mutex

我正在做一个工作,要求我执行以下操作: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);
}

编辑:执行此操作的正确方法是让thread2也调用inputThread并在while循环中锁定互斥锁,而while循环之后写另一个语句写入文件并在此之后关闭互斥锁吗?就像我必须在同一个函数中执行两项操作一样?

2 个答案:

答案 0 :(得分:2)

互斥锁在一组线程中提供了 MUT 相互 EX 。总体思路是,每个线程在执行必须将所有其他线程都排除在外的操作之前,将其锁定(相同)互斥锁,然后在完成操作后将其解锁。一次只能有一个线程将互斥锁保持锁定,因此排除在外。

此外,互斥锁还提供了内存屏障语义,以便确保在释放互斥锁之前由任何线程执行的对内存的写操作在互锁锁定互斥锁之后都可以被其他线程看到。如果不使用互斥锁或其他各种同步对象,则不能保证是这种情况。

您需要这两个属性。您需要编写者查看读取器读取的值,并且需要它等待读取器读取每个值之后才尝试写入它。您还需要读取器在每次读取之后等待,直到写入器写入了读取的值,以免在写入器有机会写入之前将其替换为新值。因此,每个线程仅在保持互斥锁处于锁定状态时才必须访问变量value,但必须在每次访问后解锁互斥锁以允许其他线程继续进行。

不幸的是,仅使用互斥体不足以解决您的问题。它们可以阻止线程同时运行,但是它们本身无法使线程交替进行,这就是问题所在。你需要。互斥锁通常与另一种同步对象(“条件变量”)结合使用,以使每个线程在应该且仅在应该运行时才运行。 CV正常使用,通常是那里的顶篷,但是它需要与互斥锁一起使用。

您可以在SO上找到许多答案,也可以找到许多有关如何使用互斥体和CV使线程正确轮换的网络教程。您可以尝试对“生产者消费者”使用Google搜索,因为这是您要解决的问题类别的通用名称。将“互斥体”和“条件变量”放入搜索词中,您应该在点击率最高的几条中获得金牌。

答案 1 :(得分:1)

您想在尝试使用要保护的变量进行任何操作之前锁定互斥锁,其中包括计数功能。

我现在没有可用的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);
}

让我知道您是否对此有任何疑问。

该作业似乎正在尝试引入生产者-消费者问题。我认为,进一步阅读该书对将来会有所帮助。

重新阅读您的答案后,我认为看生产者-消费者问题正是您想要做的。如果按照编辑中的说明进行操作,则该实现基本上是单线程的。那真的不会教你我认为这堂课试图学到的东西。

一些有用的知识

  • 循环缓冲区
  • 生产者-消费者问题
  • 学习如何避免多个互斥锁的死锁