分析
首先,我们的生产者与消费者队列需要满足同步与互斥关系,就需要一把互斥锁,以及生产者与消费者各自的条件变量。
其次,我们可以利用C++中STL里的queue
队列来进行实现,但是我们需要对push,pop进行修改,因为STL库的函数不一定能满足互斥条件。也就是不一定安全。
最后,所有资源在程序结束后一定要记得释放,否则会出现内存泄漏的风险。
程序
队列的类
/thread safe queue
class BlockQueue
{
public:
BlockQueue(size_t Capacity = CAPACITY)
{
_Capacity = Capacity;
pthread_mutex_init(&_Lock, NULL);
pthread_cond_init(&_ConsumeCond, NULL);
pthread_cond_init(&_ProductCond, NULL);
}
//push == Producer
void Push(int& Data)
{
pthread_mutex_lock(&_Lock);
//判断队列有没有满
while(IsFull())
{
pthread_cond_wait(&_ProductCond,&_Lock);
}
_Queue.push(Data);
pthread_mutex_unlock(&_Lock);
pthread_cond_signal(&_ConsumeCond);
}
//pop == consumer
void Pop(int* Data)
{
pthread_mutex_lock(&_Lock);
//判断队列有没有空
while(_Queue.empty())
{
pthread_cond_wait(&_ConsumeCond, &_Lock);
}
*Data = _Queue.front();
_Queue.pop();
pthread_mutex_unlock(&_Lock);
pthread_cond_signal(&_ProductCond);
}
~BlockQueue()
{
pthread_mutex_destroy(&_Lock);
pthread_cond_destroy(&_ConsumeCond);
pthread_cond_destroy(&_ProductCond);
}
private:
bool IsFull()
{
if(_Queue.size() == _Capacity)
return true;
return false;
}
private:
queue<int> _Queue;
size_t _Capacity; // queue max capacity
//互斥
pthread_mutex_t _Lock;//mutex
//同步
pthread_cond_t _ConsumeCond; // consume cond
pthread_cond_t _ProductCond; // product _ProductCond
};
生产者逻辑
void* Producter_start(void* arg)
{
BlockQueue* que = (BlockQueue*)arg;
int resource = 1;
while(1)
{
que->Push(resource);
resource++;
printf("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
printf("Producter_thread : [%p]\n",pthread_self());
printf("i product resource [%d]\n",resource - 1);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
}
return NULL;
}
消费者逻辑
void* Consumer_start(void* arg)
{
BlockQueue* que = (BlockQueue*)arg;
while(1)
{
int Data;
que->Pop(&Data);
printf("\n\n######################################\n");
printf("Consumer_thread : [%p]\n", pthread_self());
printf("i consume resource [%d]\n", Data);
printf("######################################\n");
}
return NULL;
}
主函数
int main()
{
BlockQueue* que = new BlockQueue();
pthread_t com_tid[THREADCOUNT], pro_tid[THREADCOUNT];
int ret = 0;
for(int i = 0; i < THREADCOUNT; i++)
{
ret = pthread_create(&com_tid[i],NULL,Consumer_start,(void*)que);
if(ret < 0)
{
perror("pthread_create Consumer error");
return 0;
}
ret = pthread_create(&pro_tid[i],NULL,Producter_start,(void*)que);
if(ret < 0)
{
perror("pthread_create Producter error");
}
}
//thread wait
for(int i = 0; i < THREADCOUNT; i++)
{
pthread_join(com_tid[i],NULL);
pthread_join(pro_tid[i],NULL);
}
//防止内存泄漏
delete que;
que = NULL;
return 0;
}
结果分析
我们发现最后的结果中,有一部分生产者与消费者信息的打印好像不是那么规范,但实际上他们都是合理的访问临界资源的。
因为线程之间的抢占式执行,使得每一个线程只能拥有一个CPU资源一小会,然后就需要让出CPU资源给其他线程。然后就会出现上图所示的执行逻辑。
源码地址
https://github.com/duchenlong/linux-text/blob/master/thread/threadqueue.cpp