pthread 执行陷入死循环

pthread execution fall in infinite loop

我正在尝试的是:

但是我的程序陷入了死循环。需要解决方案的帮助。

下面是我的源代码:

#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>   /* for ftruncate */
#include <sys/mman.h> /* for shm_ and mmap */
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h>    /* For O_* constants */

pthread_t T1, T2, T3, T4;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_one;

int fd;
int *shared_heap;
int *shared_heap2;
int *shared_heap3;
int counter = 0;

//thread one creator func
// *argv is the shared mem obj which is passed while thread is created
void* task1(void *argv) {
    int *var = (int*) argv;
    pthread_mutex_lock(&mutex);
    *var += 1;
     pthread_mutex_unlock(&mutex);
    return NULL;
} 

//thread two creator func
// *argv is the shared mem obj which is passed while thread is created
void* task2(void *argv) {
    int *var = (int*) argv;
    pthread_mutex_lock(&mutex);
    *var += 1;

    pthread_mutex_unlock(&mutex);
    //another mutex to create another shared mem obj
    pthread_mutex_lock(&mutex2);
    shared_heap2 = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,MAP_SHARED, fd, 0);
    assert(shared_heap2);
    counter++;
    //signal 
    if (counter > 0) {
     pthread_cond_signal(&cond_one);
        printf("signal is sent \n");
   }
   pthread_mutex_unlock(&mutex2);

  return NULL;
  }

 //thread four creator func
 //created from thread three
 // *argv is the shared mem obj which is passed while thread is created
 void* task4(void *argv) {
    int *var = (int*) argv;
    pthread_mutex_lock(&mutex);
    *var += 1;
    pthread_mutex_unlock(&mutex);

    pthread_mutex_lock(&mutex2);

    //waiting for signal from thread two
    while (counter > 0) {
    pthread_cond_wait(&cond_one, &mutex2);
    printf("waiting for signal. \n");
 }

    *shared_heap2 = 9;
    pthread_mutex_unlock(&mutex2);


    return NULL;  
}

////thread three creator func
void* task3(void *argv) {
     int *var = (int*) argv;
     pthread_mutex_lock(&mutex);
     *var += 1;
    pthread_mutex_unlock(&mutex);

    //thread four is create from here
     assert(pthread_create(&T4, NULL, &task4, var) == 0);
    assert(pthread_join(T4, NULL) == 0);
     return NULL;
}

int main(void) {

    pthread_cond_init(&cond_one, NULL);
     fd = shm_open("test_shared_var_heap_local", O_CREAT | O_RDWR,S_IRUSR | S_IWUSR);
    assert(fd != -1);
    assert(ftruncate(fd, sizeof(int)) == 0);
    shared_heap = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,MAP_SHARED, fd, 0);

    assert(shared_heap);

    printf("main \n");
    //assert(shared_heap);

    assert(pthread_create(&T1, NULL, &task1, shared_heap) == 0);

    assert(pthread_create(&T2, NULL, &task2, shared_heap) == 0);

    assert(pthread_create(&T3, NULL, &task3, shared_heap) == 0);
    printf("three \n");

    assert(pthread_join(T1, NULL) == 0);
    assert(pthread_join(T3, NULL) == 0);
    assert(pthread_join(T2, NULL) == 0);

     return 0;
}

But my program falls in infinite loop.

你会

while (counter > 0) {
  pthread_cond_wait(&cond_one, &mutex2);
  printf("waiting for signal. \n");
}

但是 counter 只是在 task2 中设置为 1 一次,没有理由退出 while

反正这不是一个人的问题,在task2mutext2设置了counter到 1 并发送信号,所以

  • 第一种可能task4在设置为1之前已经完成,信号没用

  • else task2 比 运行 更快并在 task4 之前获得 mutex2 ,所以当 task4 会得到 mutex2 信号已经发送,但是信号没有被缓冲所以永远不会被接收通过 task4

如果你想确保task2中受mutex2保护的代码在task4[=84之前执行=] 完成受 mutex2 保护的代码:

  • counter 仍初始化为 0 : int counter = 0;
  • in task4 when mutex2 is get just set counter to 1 and remove the useless在解锁 mutext2
  • 之前测试 if (counter > 0) 在所有情况下发送信号
  • in task2 when mutext2 is get replace the while (counter > 0) { by if (counter == 0) {

这样 :

  • if task4task2 之前得到 mutex2 因为 counter仍然是0task4等待信号(即解锁mutext2),task2可以得到mutext2 并发送信号并解锁 mutext2 并完成,task4 收到信号(锁定 mutext2) 然后解锁 mutext2 并完成
  • if task2task4 之前获取 mutext2 它设置 counter to 1 and unlock mutext2 and finished, task4 can get mutext2 and does not wait对于信号因为 counter 是 1 所以解锁 mutext2 并完成