免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5320 | 回复: 1
打印 上一主题 下一主题

[C] 【已解决】一个使用pthread_cond_wait出现死锁的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-12-19 16:02 |只看该作者 |倒序浏览
本帖最后由 vesontio 于 2014-12-19 20:12 编辑

在写一个练习,就是最典型的“生产者”(Producer)和“消费者”(Consumer)的问题,两者各用一种线程来代表,各个线程共享一个int类型的数值val。
Producer尝试将val置1,如果发现val已经为1,则wait;
Consumer则尝试将val置0,如果发现val已经为0,则wait;
任意一个线程修改val的值之后,就会呼叫pthread_cond_signal,知会其他线程。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <pthread.h>

  5. #define TH_POOL_SZ 10
  6. #define TH_NB_LOOP 100

  7. static pthread_mutex_t th_lock = PTHREAD_MUTEX_INITIALIZER;
  8. static pthread_cond_t th_cond = PTHREAD_COND_INITIALIZER;

  9. typedef struct th_data {
  10.     int val;
  11. } th_data_t;
复制代码
程序头就是如此,一个pthread_mutex_t,一个pthread_cond_t,下面的结构体是传递给线程的参数。程序会一共创建TH_POOL_SZ个“生产者”和“消费者”,每个线程尝试循环TH_NB_LOOP次,每次都试着改变val的值。

  1. static void *cons_runnable(void *arg) {
  2.     int i;

  3.     for (i = 0; i < TH_NB_LOOP; i ++) {
  4.         if (pthread_mutex_lock(&th_lock) != 0) {
  5.             perror("Failed to lock mutex");
  6.             pthread_exit(NULL);
  7.         }
  8.         printf("Consumer locked.\n");

  9.         th_data_t *data = (th_data_t *)arg;
  10.         while (data->val == 0) {
  11.             printf("Value null, consumer is waiting ...\n");
  12.             if (pthread_cond_wait(&th_cond, &th_lock) != 0) {
  13.                 perror("Failed to wait on mutex");
  14.                 pthread_exit(NULL);
  15.             }
  16.         }
  17.         printf("Consumer waked up.\n");
  18.         data->val --;
  19.         printf("Value decremented.\n");

  20.         if (pthread_mutex_unlock(&th_lock) != 0) {
  21.             perror("Failed to unlock mutex");
  22.             pthread_exit(NULL);
  23.         }
  24.         printf("Consumer unlocked.\n");

  25.         if (pthread_cond_signal(&th_cond) != 0) {
  26.             perror("Failed to signal other threads");
  27.             pthread_exit(NULL);
  28.         }
  29.         printf("Consumer signaled other threads\n");

  30.     }
  31.     printf("Consumer terminated.\n");
  32.     pthread_exit(NULL);
  33. }
复制代码
“消费者”(Consumer)的代码,没什么特别的,先加锁,发现val为0就wait,被**后就更新val的值,更新完解锁,并知会其他线程。

  1. static void *prod_runnable(void *arg) {
  2.     int i;

  3.     for (i = 0; i < TH_NB_LOOP; i ++) {
  4.         if (pthread_mutex_lock(&th_lock) != 0) {
  5.             perror("Failed to lock mutex");
  6.             pthread_exit(NULL);
  7.         }
  8.         printf("Producer locked.\n");

  9.         th_data_t *data = (th_data_t *)arg;
  10.         while (data->val == 1) {
  11.             printf("Value set, producer is waiting ...\n");
  12.             if (pthread_cond_wait(&th_cond, &th_lock) != 0) {
  13.                 perror("Failed to wait on mutex");
  14.                 pthread_exit(NULL);
  15.             }
  16.         }
  17.         printf("Producer waked up.\n");
  18.         data->val ++;
  19.         printf("Value incremented.\n");

  20.         if (pthread_mutex_unlock(&th_lock) != 0) {
  21.             perror("Failed to unlock mutex");
  22.             pthread_exit(NULL);
  23.         }
  24.         printf("Producer unlocked.\n");

  25.         if (pthread_cond_signal(&th_cond) != 0) {
  26.             perror("Failed to signal other threads");
  27.             pthread_exit(NULL);
  28.         }
  29.         printf("Producer signaled other threads.\n");
  30.     }
  31.     printf("Producer terminated.\n");
  32.     pthread_exit(NULL);
  33. }
复制代码
“生产者”(Producer)的代码基本就是和“消费者”(Consumer)反过来。
  1. int main (void) {

  2.     int i;
  3.     th_data_t data;

  4.     pthread_t th_pool_cons[TH_POOL_SZ];
  5.     pthread_t th_pool_prod[TH_POOL_SZ];
  6.     data.val = 0;

  7.     for (i = 0; i < TH_POOL_SZ; i ++) {
  8.         if (pthread_create(&th_pool_cons[i], NULL, cons_runnable, &data) != 0) {
  9.             perror("Failed to create consumer thread");
  10.             return -1;
  11.         }
  12.         if (pthread_create(&th_pool_prod[i], NULL, prod_runnable, &data) != 0) {
  13.             perror("Failed to create producer thread");
  14.             return -1;
  15.         }
  16.     }
  17.     printf("%d threads created.\n", TH_POOL_SZ * 2);

  18.     for (i = 0; i < TH_POOL_SZ; i ++) {
  19.         if (pthread_join(th_pool_cons[i], NULL) != 0) {
  20.             perror("Failed to join consumer thread");
  21.             return -1;
  22.         }
  23.     }
  24.     for (i = 0; i < TH_POOL_SZ; i ++) {
  25.         if (pthread_join(th_pool_prod[i], NULL) != 0) {
  26.             perror("Failed to join producer thread");
  27.             return -1;
  28.         }
  29.     }
  30.     printf("%d threads joined.\n", TH_POOL_SZ * 2);

  31.     printf("Final value of data: %d.\n", data.val);
  32.     printf("Fin.\n");
  33.     return 0;
  34. }
复制代码
main函数的话基本就是创建几个线程,然后等着join他们。最后的结果出来,理论上val等于0。但是每次都是在某个“消费者”(Consumer)等待的时候就卡死不动了。
前前后后看了几遍也不知道问题出在神马地方。

希望各路大神们帮帮看看,谢谢!

论坛徽章:
0
2 [报告]
发表于 2014-12-19 20:11 |只看该作者
本帖最后由 vesontio 于 2014-12-19 20:12 编辑

已经解决,应当用pthread_cond_broadcast(),而不是pthread_cond_signal(),后者如果没有叫醒正确的线程,会出现所有线程都在wait的情况。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP