gpt4 book ai didi

c - pthread_cond_signal() 没有给信号线程足够的时间运行

转载 作者:太空宇宙 更新时间:2023-11-04 07:48:11 26 4
gpt4 key购买 nike

调用 pthread_cond_signal 的线程在释放信号线程之前重新获取互斥体。

下面的代码显示了手头问题的一个简单示例。主线程将持有锁,创建工作线程,然后进入一个循环,在数据进入时打印数据。它通过条件变量发出运行信号。

工作线程会进入一个循环,生成数据,获取锁,写入数据,然后向主线程发送信号。

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int data = 0;

void *thread(void *arg) {
int length = *(int *) arg;
for (int i = 0; i < length; i++) {
// Do some work
pthread_mutex_lock(&lock);
data = i;
fprintf(stdout, "Writing\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}


int main(int argc, const char *argv[]) {
pthread_t worker;
int length = 4;

pthread_mutex_lock(&lock);
pthread_create(&worker, 0, thread, &length);

for (int i = 0; i < length; i++) {
fprintf(stdout, "Waiting\n");
pthread_cond_wait(&cond, &lock);
fprintf(stdout, "read data: %d\n", data);
}
pthread_mutex_unlock(&lock);

pthread_join(worker, NULL);
return 0;
}

这将给出以下输出:

Waiting
Writing
Writing
Writing
Writing
read data: 3
Waiting

预期行为:主线程持有互斥锁,只有在等待时才释放它。然后,工作线程将写入其数据并向主线程发出信号。主线程将立即锁定信号互斥量,然后读取数据并返回等待,释放互斥量。同时,工作线程将完成其工作并一直等待,直到主线程再次等待写入其数据并向其发出信号。

相反,似乎工作线程在调用信号后立即获得互斥锁,很少让主线程获得访问权限。如果我在工作线程中放置一个 sleep 代替 //Do some work 那么它将给出预期的输出。

最佳答案

向条件变量发出信号不会给予任何类型的优先级以将互斥锁锁定到等待该条件变量的线程。这意味着至少一个等待条件变量的线程将开始尝试获取互斥锁,以便它可以从 pthread_cond_wait() 返回。信号线程将继续执行,并且可以轻松地首先重新获取互斥量,如您所见。

你永远不应该有一个条件变量,它没有你正在等待的一些共享状态的实际条件 - 从 pthread_cond_wait() 返回并不意味着线程一定要继续,这意味着它应该检查它正在等待的条件是否为真。这就是它们被称为条件变量的原因。

在这种情况下,你的写入线程想要等待的状态是“主线程已经消耗了我写入的最后一个数据。”。但是,您的读取(主)线程需要等待一个条件 - “写入线程已写入一些新数据”。您可以使用标志变量来实现这两个条件,该标志变量指示一些新的、未使用的数据已写入 data 变量。该标志开始未设置,由写入线程在更新 data 时设置,并在主线程从 data 读取时取消设置。写入线程等待标志被取消设置,读取线程等待标志被设置。

通过这种安排,您也不需要在启动写入线程时锁定互斥量 - 线程启动的顺序无关紧要,因为无论哪种方式,一切都是一致的。

更新后的代码如下所示:

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int data = 0;
int data_available = 0;

void *thread(void *arg)
{
int length = *(int *) arg;
for (int i = 0; i < length; i++) {
// Do some work
pthread_mutex_lock(&lock);
fprintf(stdout, "Waiting to write\n");
while (data_available)
pthread_cond_wait(&cond, &lock);
fprintf(stdout, "Writing\n");
data = i;
data_available = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}


int main(int argc, const char *argv[])
{
pthread_t worker;
int length = 4;

pthread_create(&worker, 0, thread, &length);

for (int i = 0; i < length; i++) {
pthread_mutex_lock(&lock);
fprintf(stdout, "Waiting to read\n");
while (!data_available)
pthread_cond_wait(&cond, &lock);
fprintf(stdout, "read data: %d\n", data);
data_available = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}

pthread_join(worker, NULL);
return 0;
}

当然,线程最终会同步工作 - 但本质上您有一个最大队列长度为 1 的生产者-消费者,所以这是意料之中的。

关于c - pthread_cond_signal() 没有给信号线程足够的时间运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55602207/

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