题目:使用多线程,要求按序打印出4次abcd
1.只使用互斥量mutex
忙等,直到能够获得进入临界区的条件
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#define THRNUM 4
//print abcd to stdout
//4个互斥量之间协作
static pthread_mutex_t mut[THRNUM];
static int next(int n){
if(n + 1 == THRNUM){
return 0;
}
return n + 1;
}
static void* thr_fun(void* p){
int n = (int)p;// n = 0 1 2 3
int c = 'a' + n;
//lock a,unlock b
int m = 4;
while(m--){
pthread_mutex_lock(mut + n);
write(1, &c, 1);
//解锁下一个字符的互斥量
pthread_mutex_unlock(mut + next(n));
}
pthread_exit(NULL);
}
int main(){
pthread_t tid[THRNUM];
int err,i;
for(i = 0; i < THRNUM; ++i){
pthread_mutex_init(mut + i, NULL);
pthread_mutex_lock(mut + i);
err = pthread_create(tid + i, NULL, thr_fun, (void*)i);
if(err){
fprintf(stderr, "pthread_create():%s\n", strerror(err));
exit(1);
}
}
//最后别忘记释放自己的锁
pthread_mutex_unlock(mut + 0);
alarm(5);
//回收资源
for(i = 0; i < THRNUM; ++i){
pthread_join(tid[i], NULL);
}
exit(0);
}
2.使用互斥量mutex和条件变量cond
互斥量和条件变量配合变成通知法
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#define THRNUM 4
//print abcd to stdout
static int num = 0;
//静态初始化
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//使用cond变成通知法
static int next(int n){
if(n + 1 == THRNUM){
return 0;
}
return n + 1;
}
static void* thr_fun(void* p){
//n == thread arg
int n = (int)p;//0 1 2 3
int c = 'a' + n;
//lock a,unlock b
int m = 4;
//char buf[4];
while(m--){
//pthread_mutex_lock(mut + n);
pthread_mutex_lock(&mut);
//临界区内等待,发通知
//锁住的是自己的锁
while(num != n){
//等待 mum = n
//抢到的锁,但是不是自己的锁则等待
pthread_cond_wait(&cond, &mut);
}
write(1, &c, 1);
//puts(" ");
//fprintf(stdout, &c, NULL);
//取下一个
num = next(num);
//a在打印, bcd在等待
//唤醒的也不知道是哪个线程,避免不了产生惊群
pthread_cond_broadcast(&cond);//发通知
pthread_mutex_unlock(&mut);
}
pthread_exit(NULL);
}
int main(int argc, char* argv[]){
pthread_t tid[THRNUM];
int err,i;
for(i = 0; i < THRNUM; ++i){
//pthread_mutex_init(mut + i, NULL);
//pthread_mutex_lock(mut + i);
err = pthread_create(tid + i, NULL, thr_fun, (void*)i);
if(err){
fprintf(stderr, "pthread_create():%s\n", strerror(err));
exit(1);
}
}
//pthread_mutex_unlock(mut + 0);
alarm(5);// 非正常结束
//正常结束:添加一个处理函数,注册行为,join and destroy
for(i = 0; i < THRNUM; ++i){
pthread_join(tid[i], NULL);
}
pthread_mutex_destroy(&mut);
pthread_cond_destroy(&cond);
exit(0);
}
以上编译得到的结果为:
abcdabcdabcdabcd
总结:
(1)第一种方法注意点,最后别忘记释放a的锁
(2)第二种方法,使用条件变量变成了通知法,避免了忙等的情况
存在问题:可能线程惊群
产生条件:当一个线程解锁并通知其他线程的时候,就会出现惊群的现象
正常的用法:
所有线程共用一个锁,共用一个条件变量
当pthread_cond_signal通知时,就可能会出现惊群
解决惊群的方法:
所有线程共用一个锁,每个线程有自已的条件变量
pthread_cond_signal通知时,定向通知某个线程的条件变量,不会出现惊群