我正在研究生产者和消费者的问题。我创建了一个生成器来将东西放入有界缓冲区并使用多个使用者从缓冲区中获取数据。为了检查每个消费者是否正在工作,我给他们每个人一个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
此处仅使用一个消费者。我试过“睡觉”,它可以给我输出我预期但导致执行缓慢。我想知道是否有更好的方法来解决这个问题?
答案 0 :(得分:4)
你给每个线程一个指向局部变量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
答案 1 :(得分:1)
你给他们一个变量hbitmap
的引用,它在循环中发生变化。它执行得如此之快,以至于每个线程都将其视为5。
你仍然得到五个线程,你只是错误地发送了这个号码。