linux – 为什么sleep()获取pthread_mutex_lock后会阻塞整个程序
在我的测试程序中,我启动了两个线程,每个线程只执行以下逻辑:
1) pthread_mutex_lock() 2) sleep(1) 3) pthread_mutex_unlock() 但是,我发现经过一段时间后,两个线程中的一个将永远阻塞pthread_mutex_lock(),而另一个线程正常工作.这是一种非常奇怪的行为,我认为这可能是一个潜在的严重问题.通过Linux手册,获取pthread_mutex_t时不禁止sleep().所以我的问题是:这是一个真正的问题还是我的代码中有任何错误? 以下是测试程序.在代码中,第一个线程的输出定向到stdout,而第二个线程定向到stderr.所以我们可以检查这两个不同的输出,看看线程是否被阻塞. 我在linux内核(2.6.31)和(2.6.9)上测试过它.两个结果都是一样的. //======================= Test Program =========================== #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <pthread.h> #define THREAD_NUM 2 static int data[THREAD_NUM]; static int sleepFlag = 1; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static void * threadFunc(void *arg) { int* idx = (int*) arg; FILE* fd = NULL; if (*idx == 0) fd = stdout; else fd = stderr; while(1) { fprintf(fd,"n[%d]Before pthread_mutex_lock is calledn",*idx); if (pthread_mutex_lock(&mutex) != 0) { exit(1); } fprintf(fd,"[%d]pthread_mutex_lock is finisheded. Sleep some timen",*idx); if (sleepFlag == 1) sleep(1); fprintf(fd,"[%d]sleep donenn",*idx); fprintf(fd,"[%d]Before pthread_mutex_unlock is calledn",*idx); if (pthread_mutex_unlock(&mutex) != 0) { exit(1); } fprintf(fd,"[%d]pthread_mutex_unlock is finisheded.n",*idx); } } // 1. compile // gcc -o pthread pthread.c -lpthread // 2. run // 1) ./pthread sleep 2> /tmp/error.log # Each thread will sleep 1 second after it acquires pthread_mutex_lock // ==> We can find that /tmp/error.log will not increase. // or // 2) ./pthread nosleep 2> /tmp/error.log # No sleep is done when each thread acquires pthread_mutex_lock // ==> We can find that both stdout and /tmp/error.log increase. int main(int argc,char *argv[]) { if ((argc == 2) && (strcmp(argv[1],"nosleep") == 0)) { sleepFlag = 0; } pthread_t t[THREAD_NUM]; int i; for (i = 0; i < THREAD_NUM; i++) { data[i] = i; int ret = pthread_create(&t[i],NULL,threadFunc,&data[i]); if (ret != 0) { perror("pthread_create errorn"); exit(-1); } } for (i = 0; i < THREAD_NUM; i++) { int ret = pthread_join(t[i],(void*)0); if (ret != 0) { perror("pthread_join errorn"); exit(-1); } } exit(0); } 这是输出: 在程序启动的终端上: root@skyscribe:~# ./pthread sleep 2> /tmp/error.log [0]Before pthread_mutex_lock is called [0]pthread_mutex_lock is finisheded. Sleep some time [0]sleep done [0]Before pthread_mutex_unlock is called [0]pthread_mutex_unlock is finisheded. ... 在另一个终端上看到文件/tmp/error.log root@skyscribe:~# tail -f /tmp/error.log [1]Before pthread_mutex_lock is called 并且没有新的行从/tmp/error.log中输出 解决方法
这是使用互斥锁的错误方法.线程不应该持有互斥锁的时间超过它不拥有它的时间,特别是如果它在按住互斥锁时休眠.锁定互斥锁没有FIFO保证(出于效率原因).
更具体地说,如果线程1在线程2等待它时解锁互斥锁,则它使线程2可运行但这不会强制调度程序抢占线程1或使线程2立即运行.最有可能的是,它不会因为线程1最近睡过了.当线程1随后到达pthread_mutex_lock()调用时,通常会允许它立即锁定互斥锁,即使有一个线程正在等待(并且实现可以知道它).当线程2在此之后唤醒时,它会发现互斥锁已经锁定并重新进入休眠状态. 最好的解决方案是不要长时间持有互斥锁.如果无法做到这一点,请考虑将需要锁定的操作移动到单个线程(不需要锁定)或使用条件变量唤醒正确的线程. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |