jelasin 的学生作业:
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int number = 0;//共享变量
int total_of_produce = 0; // 总的生产产品的数量
int total_of_consume = 0; // 总的消费产品的数量
bool done = false;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *product_handler(void *arg)
{
int cnt = atoi((char *)arg);
int i,tmp;
for(i = 0;i < cnt;i++)
{
pthread_mutex_lock(&mtx);
printf("线程 [%ld] 生产一个产品,产品数量为:%d\n",pthread_self(),++number);
pthread_cond_broadcast(&cond); // 唤醒消费者线程
pthread_mutex_unlock(&mtx);
}
pthread_exit((void *)0);
}
void* consumer_handler(void *arg)
{
pthread_mutex_lock(&mtx);
while(number == 0) // 当产品数量为 0时,让线程阻塞,并释放锁,这里一般设置循环,防止没有重新获取到锁
pthread_cond_wait(&cond,&mtx);
while(number > 0)
{
total_of_consume++; // 消费产品总数
printf("消费一个产品,产品数量为:%d\n",--number);
done = total_of_consume >= total_of_produce; // 判断消费者数量与产品数量
}
pthread_mutex_unlock(&mtx); // 消费者消费完成之后,释放锁
pthread_exit((void *)0);
}
int main(int argc,char *argv[])
{
pthread_t tid;
int i;
int err;
for (i = 1;i < argc;i++)
{
total_of_produce += atoi(argv[i]); // 生产数量的总和
err = pthread_create(&tid,NULL,product_handler,(void *)argv[i]);
if (err != 0)
{
perror("[ERROR] pthread_create(): ");
exit(EXIT_FAILURE);
}
pthread_detach(tid); // 线程分离,不等待线程结束
}
while (done == false)
{
err = pthread_create(&tid,NULL,consumer_handler,NULL);
if (err != 0)
{
perror("[ERROR] pthread_create(): ");
exit(EXIT_FAILURE);
}
pthread_detach(tid); // 线程分离,不等待线程结束
sleep(1); // 等待1秒钟,防止消费者线程阻塞
}
return 0;
}
➜ 5 ./main 10 10 10
线程 [138990789330496] 生产一个产品,产品数量为:1
线程 [138990789330496] 生产一个产品,产品数量为:2
线程 [138990789330496] 生产一个产品,产品数量为:3
线程 [138990789330496] 生产一个产品,产品数量为:4
线程 [138990789330496] 生产一个产品,产品数量为:5
线程 [138990642529856] 生产一个产品,产品数量为:6
线程 [138990642529856] 生产一个产品,产品数量为:7
线程 [138990757873216] 生产一个产品,产品数量为:8
线程 [138990757873216] 生产一个产品,产品数量为:9
线程 [138990757873216] 生产一个产品,产品数量为:10
线程 [138990757873216] 生产一个产品,产品数量为:11
线程 [138990757873216] 生产一个产品,产品数量为:12
线程 [138990757873216] 生产一个产品,产品数量为:13
线程 [138990757873216] 生产一个产品,产品数量为:14
线程 [138990757873216] 生产一个产品,产品数量为:15
线程 [138990757873216] 生产一个产品,产品数量为:16
线程 [138990757873216] 生产一个产品,产品数量为:17
消费一个产品,产品数量为:16
消费一个产品,产品数量为:15
消费一个产品,产品数量为:14
消费一个产品,产品数量为:13
消费一个产品,产品数量为:12
消费一个产品,产品数量为:11
消费一个产品,产品数量为:10
消费一个产品,产品数量为:9
消费一个产品,产品数量为:8
消费一个产品,产品数量为:7
消费一个产品,产品数量为:6
消费一个产品,产品数量为:5
消费一个产品,产品数量为:4
消费一个产品,产品数量为:3
消费一个产品,产品数量为:2
消费一个产品,产品数量为:1
消费一个产品,产品数量为:0
线程 [138990789330496] 生产一个产品,产品数量为:1
线程 [138990789330496] 生产一个产品,产品数量为:2
线程 [138990642529856] 生产一个产品,产品数量为:3
线程 [138990789330496] 生产一个产品,产品数量为:4
线程 [138990789330496] 生产一个产品,产品数量为:5
线程 [138990789330496] 生产一个产品,产品数量为:6
线程 [138990642529856] 生产一个产品,产品数量为:7
线程 [138990642529856] 生产一个产品,产品数量为:8
线程 [138990642529856] 生产一个产品,产品数量为:9
线程 [138990642529856] 生产一个产品,产品数量为:10
线程 [138990642529856] 生产一个产品,产品数量为:11
线程 [138990642529856] 生产一个产品,产品数量为:12
线程 [138990642529856] 生产一个产品,产品数量为:13
消费一个产品,产品数量为:12
消费一个产品,产品数量为:11
消费一个产品,产品数量为:10
消费一个产品,产品数量为:9
消费一个产品,产品数量为:8
消费一个产品,产品数量为:7
消费一个产品,产品数量为:6
消费一个产品,产品数量为:5
消费一个产品,产品数量为:4
消费一个产品,产品数量为:3
消费一个产品,产品数量为:2
消费一个产品,产品数量为:1
消费一个产品,产品数量为:0
发送信号,通知等待在条件上的线程,然后解锁互斥量。注意范例代码中先发送信号,然后解锁互斥量,这个顺序不是必须的,也可以颠倒。标准允许任意顺序执行这两个调用。先通知条件变量、后解锁互斥量,效率会比先解锁、后通知条件变量低。因为先通知后解锁,执行pthread_cond_wait的线程可能在互斥量已然处于加锁状态的时候醒来,发现互斥量仍然没有解锁,就会再次休眠,从而导致了多余的上下文切换。某些实现使用等待变形(wait morphing)来优化这个问题:并不真正地唤醒执行pthread_cond_wait的线程,而是将线程从条件变量的等待队列转移到互斥量的等待队列上,从而消除无谓的上下文切换。
glibc对pthread_cond_broadcast做了类似的优化,即只唤醒一个线程,将其他线程从条件变量的等待队列搬移到了互斥量的等待队列中。
先解锁、后通知条件变量虽然可能会有性能上的优势,但是也会带来其他的问题。如果存在一个高优先级的线程,既等待在互斥量上,也等待在条件变量上;同时还存在一个低优先级的线程,只等待在互斥量上。一旦先解锁互斥量,低优先级的进程就可能会抢先获得互斥量,待调用pthread_cond_signal之后,高优先级的进程会发现互斥量已经被低优先级的进程抢走了。