gpt4 book ai didi

linux - 为什么获取pthread_mutex_lock后sleep()会阻塞整个程序?

转载 作者:IT王子 更新时间:2023-10-29 01:10:47 24 4
gpt4 key购买 nike

在我的测试程序中,我启动了两个线程,每个线程只执行以下逻辑:

    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 called\n", *idx);
if (pthread_mutex_lock(&mutex) != 0) {
exit(1);
}
fprintf(fd, "[%d]pthread_mutex_lock is finisheded. Sleep some time\n", *idx);
if (sleepFlag == 1)
sleep(1);
fprintf(fd, "[%d]sleep done\n\n", *idx);


fprintf(fd, "[%d]Before pthread_mutex_unlock is called\n", *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 error\n");
exit(-1);
}
}

for (i = 0; i < THREAD_NUM; i++) {
int ret = pthread_join(t[i], (void*)0);
if (ret != 0) {
perror("pthread_join error\n");
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 在此之后醒来时,它会发现互斥体已经被锁定并返回休眠状态。

最好的解决方案是不要将互斥量保持那么久。如果这不可能,请考虑将需要锁的操作移至单个线程(消除对锁的需求)或使用条件变量唤醒正确的线程。

关于linux - 为什么获取pthread_mutex_lock后sleep()会阻塞整个程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8091117/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com