问题遇到的现象和发生背景
Linux编写多线程代码时遇到的问题:使用的pthread_join()并没有对所有线程资源进行回收,仅回收了部分线程后,一直处于阻塞状态。
问题相关代码
#include<iostream>
#include<pthread.h>
#include<signal.h>
#include<unistd.h>
using namespace std;
#define N 10 // food总生产个数
#define TID_NUM 10 // 线程个数, 如果大于3, 就会产生问题
static int food = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
int cnt1 = 0;
int cnt2 = 0;
void* thread_cook(void* arg)
{
int tid = *((int*)arg);
for (int i = 1; i <= N; ++i)
{
pthread_mutex_lock(&mutex);
++food;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
++cnt1;
}
sleep(1);
pthread_cond_broadcast(&cond); // 通知所有正在等待的人(唤醒所有处于等待队列中的线程)
return NULL;
}
void* thread_eat(void* arg)
{
pthread_t tid = *((pthread_t*)arg);
while (cnt2 < N) //可能有晚来的线程, 那么可能会看到今天的食物发完了 "那没我事了,先走了"。
{
pthread_mutex_lock(&mutex);
if (food <= 0) pthread_cond_wait(&cond, &mutex);
if (cnt2 == N) // 唤醒却被告知,食物已经发完了啦
{
break; // 退场(回收线程资源)
}
cout << tid << " eat 1, left " << --food << endl;
++cnt2;
pthread_mutex_unlock(&mutex);
sleep(0.01); // 使多线程交替执行
}
return NULL;
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_t tid[TID_NUM];
pthread_create(&tid[0], NULL, thread_cook, (void*)&tid[0]);
for (int i = 1; i < TID_NUM; ++i)
pthread_create(&tid[i], NULL, thread_eat, (void*)&tid[i]);
/*
不理解:下面的pthread_join()为什么会存在个别线程无限阻塞的情况,
解决方案:将线程个数减少到3的时候,就没有问题了,但问题所在仍未知
*/
for (int i = 0; i < TID_NUM; ++i)
{
pthread_join(tid[i], NULL); // 真正回收joinable线程资源
cout << i << endl;
}
cout << "created food: " << cnt1 << endl;
cout << "eat total: " << cnt2 << endl;
pthread_mutex_destroy(&mutex);
return 0;
}
运行结果及报错内容
程序一直阻塞无法退出,上图中的0和1结果表明,pthread_join仅回收了两个线程的资源。
我的解答思路和尝试过的方法
方法1:因为pthread_cook线程和pthread_eat线程不一样,pthread_cook线程一定要在pthread_eat线程退出之前,保证它食物都能被pthread_eat得到。所以pthread_cook通过pthread_join()单独进行回收,其余的pthread_eat线程由pthread_detach进行回收,就需要将pthread_eat线程从连接的状态(joinable)转变成分离状态(detached),我采用的是pthread_attr_init()方法,将pthread_create()中的attr属性设置为PTHREAD_CREATE_DETACHED,之后在线程执行语句的最后通过pthread_detach(pthread id)就可以对其进行回收了,从而达到下图展示的结果。
方法2:和上面方法一大致一样,只不过是将pthread_detach(self())置于pthread_eat线程开始位置,然后在main函数后面对其所有线程执行pthread_detach(线程id)。
方法3(疑惑所在):
对于pthread_join()函数的问题,产生疑惑,后面发现当线程个数为3的时候,即1个cook线程和2个eat线程,就不会产生上面无限阻塞的问题。这就是我主要疑惑的地方,麻烦帮忙解答一下!**