一、说明
linux的线程同步涉及:
1、互斥量
2、条件变量
3、信号灯
4、文件读写锁
信号灯很多时候被称为信号量,但个人仍觉得叫做信号灯比较好,因为可以与“SYSTEM V IPC的信号量”相区分(如有不同意见,欢迎探讨)。
二、互斥量
1、定义
互斥锁允许我们锁住某个对象(某个变量、某段代码等),使得每次只能有一个线程访问他。我们在对需要保护的对象进行操作前,先把互斥锁上锁,如果上锁成功,就不会有别的线程再来操作被保护的对象。如果上锁不成功,线程就会阻塞(可能是有别的线程已经把互斥锁锁住了),直到互斥锁被打开。从而保护了要保护的对象。
2、相关函数
a.pthread_mutex_init
函数原型:
#include
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr);
功能:初始化互斥锁
参数:mutex为pthread_mutex_t类型的变量的地址,也就是互斥锁的名字;
mutexattr为pthread_mutexattr_t类型的变量地址,用于设置锁的属性,默认可以设为NULL;
返回:成功0,错误返回错误代码。
备注:初始化互斥锁还有个简便的方法,比如对 pthread_mutex_t a; 进行初始化,则直接写成:pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER; 即可。
b.pthread_mutex_destroy
函数原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁互斥锁
参数:mutex为要销毁的互斥锁的地址
返回:成功0,错误返回错误代码。
c.pthread_mutex_lock
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex));
功能:上锁
参数:同上
返回:同上
d.pthread_mutex_unlock
函数原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:同上
返回:同上
3、例程
#include
#include
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
int cnt=0;
void *func1(void *b)
{
int a=2000;
usleep(rand()%2000);
while(a--)
{
printf("11111=%d.\n",a);
printf("\tpthread 1 start to lock.\n");
pthread_mutex_lock (&mylock);
printf("\tpthread 1 locked.\n");
cnt++;
printf("\t++cnt=%d\n",cnt);
printf("\tpthread 1 start to unlock.\n");
pthread_mutex_unlock (&mylock);
printf("\tpthread 1 unlocked.\n");
}
}
void *func2(void *b)
{
int a=2000;
usleep(rand()%2000);
while(a--)
{
printf("22222=%d.\n",a);
printf("\tpthread 2 start to lock.\n");
pthread_mutex_lock (&mylock);
printf("\tpthread 2 locked.\n");
if(cnt>0)
{
cnt--;
printf("\t--cnt=%d\n",cnt);
}
printf("\tpthread 2 start to unlock.\n");
pthread_mutex_unlock (&mylock);
printf("\tpthread 2 unlocked.\n");
if(!cnt)
{
usleep(1);
}
}
}
int main(void)
{
pthread_t a,b;
pthread_create(&a, NULL, func1, (void*)0 );
pthread_create(&b, NULL, func2, (void*)0 );
pthread_join (a, NULL);
pthread_join (b, NULL);
return 0;
}程序中,cnt即为要保护的对象,两个线程,同一时刻只能有一个线程在访问这个对象。
三、条件变量
1、定义
条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定条件的发生。条件本身受互斥量的保护,线程在改变条件状态前,必须先锁住互斥量,其他线程在获得互斥量之前不会觉察到这种变化(因为互斥量被正在改变条件的线程锁着,其他线程没有获得互斥量就没有机会觉察到变化)
2、相关函数
a.pthread_cond_init
函数原型:
int pthread_cond_init (pthread_cond_t * cond,const pthread_condattr_t *cond_attr);
功能:初始化条件变量
参数:cond条件变量名的地址
cond_attr为条件变量的属性
返回:成功0,错误返回错误编号
备注:简便的初始化方法:pthread_cond_t a = PTHREAD_COND_INITIALIZER;
b.pthread_cond_destroy
函数原型:
int pthread_cond_destroy (pthread_cond_t *cond);
功能:销毁条件变量
参数:cond条件变量名的地址
返回:成功0,错误返回错误代码
c.pthread_cond_wait
函数原型:
int pthread_cond_wait (pthread_cond_t *cond,pthread_mutex_t *mutex);
功能:等待互斥锁mutex下的条件cond的发生
参数:cond为要等待的条件变量
mutex为保护条件变量的互斥锁
返回:成功0,错误返回错误代码
d.pthread_cond_signal
函数原型:
int pthread_cond_signal (pthread_cond_t *cond);
功能:发送条件变量cond
参数:cond为要发送的条件变量
返回:成功0,否则返回错误编号 备注:
只通知某一个等待该条件的线程
e.pthread_cond_broadcast
功能:发送条件变量cond
参数:cond为要发送的条件变量
返回:成功0,否则返回错误编号
备注:通知所有等待该条件的线程
3、例程(与某嵌入式面试题类似:三个线程各自打印A、B、C,要求按顺序ACBCACBC输出)
#include
#include
#include
int sequence=1;
int eat = 1;
pthread_mutex_t productor_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t productor_mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t my_cond1 = PTHREAD_COND_INITIALIZER;
void *productor1()
{
int my_sequence = 1;
while(1)
{
pthread_mutex_lock(&productor_mutex);
while(sequence!=my_sequence)
{
pthread_cond_wait (&my_cond, &productor_mutex);
}
pthread_mutex_lock(&productor_mutex1);
while(eat!=1)
{
pthread_cond_wait (&my_cond1, &productor_mutex1);
}
printf("A ");
eat=0;
pthread_cond_broadcast (&my_cond1);
pthread_mutex_unlock (&productor_mutex1);
sequence=2;
pthread_cond_broadcast(&my_cond);
pthread_mutex_unlock (&productor_mutex);
}
return 0;
}
void *productor2()
{
int my_sequence=2;
while(1)
{
pthread_mutex_lock(&productor_mutex);
while(sequence!=my_sequence)
{
pthread_cond_wait (&my_cond, &productor_mutex);
}
pthread_mutex_lock(&productor_mutex1);
while(eat!=1)
{
pthread_cond_wait (&my_cond1, &productor_mutex1);
}
printf("B ");
eat=0;
pthread_cond_broadcast (&my_cond1);
pthread_mutex_unlock (&productor_mutex1);
sequence=1;
pthread_cond_broadcast (&my_cond);
pthread_mutex_unlock (&productor_mutex);
}
return 0;
}
void *consumer()
{
long a=200;
while(a--)
{
pthread_mutex_lock(&productor_mutex1);
while(eat!=0)
{
pthread_cond_wait (&my_cond1, &productor_mutex1);
}
printf("C ");
eat=1;
pthread_cond_broadcast (&my_cond1);
pthread_mutex_unlock (&productor_mutex1);
}
return 0;
}
int main(void)
{
pthread_t pth1=0,pth2=0,pth3=0;
int err=-1;
void *tret=NULL;
err = pthread_create(&pth1,NULL,productor1,NULL);
if(err)
{
printf("creat pthread productor failed!\n");
exit(1);
}
err = pthread_create(&pth2,NULL,productor2,NULL);
if(err)
{
printf("creat pthread productor failed!\n");
exit(1);
}
err = pthread_create(&pth3,NULL,consumer,NULL);
if(err)
{
printf("creat pthread consumer failed!\n");
exit(1);
}
err = pthread_join(pth3,&tret);
if(err)
printf("can't join pthread consumer!\n");
else
printf("pthread consumer exit with %d!\n",(int)tret);
pthread_cancel(pth1);
pthread_cancel(pth2);
exit(0);
}
四、信号灯
1、定义
又叫做计数信号量,post一次信号量的值+1;wait一次,信号量的值-1,如果信号量的值已经为0,则wait将阻塞直至信号量的值>0;
2、相关函数
a.sem_init
函数原型:
#include
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量
参数:sem为要初始化的信号量地址
value为初始化设置的值
返回:X?
b.sem_destroy
函数原型:
int sem_destroy(sem_t * sem);
功能:销毁信号量
参数:sem要销毁的信号量地址
返回:X?
c.sem_post
函数原型:
int sem_post(sem_t * sem);
功能:信号量值+1
参数:
返回:
d.sem_wait
函数原型:
int sem_wait(sem_t * sem);
功能:信号量值-1
参数:sem要销毁的信号量地址
返回:X?
e.sem_getvalue
函数原型:
int sem_getvalue(sem_t * sem);
功能:获取信号量当前值
参数:
返回:X?
3、例程
五、文件读写锁
1、定义
2、相关函数
3、例程