我正在研究生产者和消费者问题。我创建了一个生产者来将内容放入有界缓冲区中,并使用多个消费者从缓冲区中获取数据。为了检查每个消费者是否在工作,我给他们每个人一个 ID 并让他们打印出来。
以下是创建多个消费者的代码。
#define CONSUMER_NUM 5;
pthread_t consumer[CONSUMER_NUM];
for(i=0;i<CONSUMER_NUM;i++){
int t = i;
pthread_create(&consumer[i],NULL,fun_consumer,(void*)&t);
} // pass i to the function fun_consumer to be an id of the thread
我期望的可能是这样的:
Consumer 1
Consumer 2
Consumer 3
Consumer 4
Consumer 5
我知道由于线程的随机执行,输出通常不会像这样。我在这里期望的是大多数消费者将开始工作。然而,事实是打印出来的程序是这样的:
Consumer 5
Consumer 5
Consumer 5
Consumer 5
Consumer 5
这里只用了一个消费者。我试过“ sleep ”,它可以给我预期但导致执行缓慢的输出。我想知道是否有更好的方法来解决这个问题?
最佳答案
您为每个线程提供了一个指向局部变量 i
的指针。随着每次循环迭代,i
都在变化 - 到线程实际启动和就绪循环完成时,i
等于 5(最后一个值)。
然而,这只是众多潜在结果之一。您的线程 ID 确实可以读取任何内容,因为您在此代码中有一个经典的数据竞争。您正在从多个线程访问一个变量,该变量不受任何保护。如果运气好的话,甚至可以读到 42。
解决方案。
为每个线程动态创建一个新变量并传递该变量的地址(您需要在线程中删除以防止内存泄漏),或者将整数变量转换为指针并将该值提供给线程。要(某种程度上)以可移植的方式执行此操作,您的 i
实际上应该是 uintptr_t
类型,而不是 unsigned int
。
如何每次都创建新变量的示例:
for (i=0 ; i<CONSUMER_NUM; ++i) {
int* id = malloc(sizeof(int));
*id = i;
pthread_create(&consumer[i],NULL,fun_consumer, id);
}
...
void* fun_consumer(void* arg) {
int id = *(int*)(arg);
free(arg)
// rest of code
关于C pthread : Multiple Threads but only ONE thread is used,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36437064/