目录
线程同步的其它方法:互斥锁、信号量见此文章:线程同步的方法1——互斥锁、信号量
一、条件变量
1.1概念
1.2条件变量接口
头文件:#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
//将条件变量添加到等待队列中,阻塞,等待被唤醒;第一个参数是条件变量的地址,第二个参数是互斥锁:也就是说条件变量往往伴随着互斥锁的使用;
int pthread_cond_signal(pthread_cond_t *cond);//唤醒单个线程
int pthread_cond_broadcast(pthread_cond_t*cond);//唤醒所有等待的线程
int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量
上述函数成功返回0,失败则返回错误码。
1.3 条件变量例1
主函数输入数据到全局变量buff中,主线程负责从键盘获取数据,获取到数据之后把数据写入到buff中,我们就认为条件满足了,我们就去唤醒等待着的两个线程,让其中的某一个线程将buff中的数据打印出去;
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
char buff[128]={0};
void* work_thread(void* arg)
{
char* thread_name=(char*)arg;//arg是pthread_create函数的第四个参数
while(1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);//前后必须上锁解锁,因为放在等待队列的操作不能被打断
pthread_mutex_unlock(&mutex);
if(strncmp(buff,"end",3)==0)
{
break;
}
printf("%s %s",thread_name,buff);
}
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_t id1,id2;
pthread_create(&id1,NULL,work_thread,"thread:1");
pthread_create(&id2,NULL,work_thread,"thread:2");
while(1)
{
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
pthread_cond_broadcast(&cond);
break;
}
else
{
pthread_cond_signal(&cond);
}
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
exit(0);
}
二、读写锁
读写锁保证了更高的并发性;读写锁适用读的场景比较多的场景。
2.1读写锁接口
头文件:#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t*rwlock, pthread_rwlockattr_t *attr);
//第一个参数是锁的地址,第二个参数是锁的属性
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//加读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
//解锁,不管加的读锁还是写锁,都是通过un1ock解锁;
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//销毁
上述函数成功返回0,失败则返回错误码。
读写锁的三种状态:
- 读模式下的加锁状态
- 写模式下的加锁状态
- 不加锁的状态
2.2 模拟
创建3个线程,两个线程进行读操作,一个线程进行写操作;模拟一下,让两个读操作同时操作,但是读和写是不能同时操作的。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
pthread_rwlock_t rwlock;
void* fun_read(void* arg)
{
char* s=(char*)arg;
for(int i=0;i<5;i++)
{
pthread_rwlock_rdlock(&rwlock);
printf("%s: start\n",s);
int n=rand()%3;
sleep(n);
printf("%s: end\n",s);
pthread_rwlock_unlock(&rwlock);
n=rand()%3;
sleep(n);
}
}
void* fun_write(void* arg)
{
char* s=(char*)arg;
for(int i=0;i<5;i++)
{
pthread_rwlock_wrlock(&rwlock);
printf("%s: start\n",s);
int n=rand()%3;
sleep(n);
printf("%s: end\n",s);
pthread_rwlock_unlock(&rwlock);
n=rand()%3;
sleep(n);
}
}
int main()
{
pthread_rwlock_init(&rwlock,NULL);
pthread_t id1,id2,id3;
pthread_create(&id1,NULL,fun_read,"第一个读线程:");
pthread_create(&id2,NULL,fun_read,"第二个读线程:");
pthread_create(&id3,NULL,fun_write,"第一个写线程:");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_join(id3,NULL);
pthread_rwlock_destroy(&rwlock);
}