造成死锁的原因:
for(int i=0;i<MAX;++i){
//加锁
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);//自己锁自己
int cur=number;
cur++;
number=cur;
printf("Thread A,id = %lu, number = %d\n",pthread_self(),number);
//解锁
pthread_mutex_unlock(&mutex);
usleep(10);
}
操作完成之后,一定要解锁。
1. 读写锁是几把锁?
(1)一把锁
(2)pthread_rwlock_t lock;
2. 读写锁的类型:
(1)读锁 - 对内存做读操作
(2)写锁 - 对内存做写操作
3. 读写锁的特性:
(1)线程A加读锁成功,又来了三个线程,做读操作,可以加锁成功【读共享 - 并行处理】
(2)线程A加写锁成功,又来了三个线程,做读操作,三个线程阻塞 【写独占 】
(3)线程A加读锁成功,又来了B线程加写锁阻塞,又来了C线程加读锁阻塞【读写不能同时;写的优先级高(写锁都阻塞了那么之后的读锁肯定阻塞)】
4. 读写锁场景练习
5、读写锁的使用场景
互斥锁 - 读写串行
读写锁:
读:并行
写:串行
程序中的读操作>>写操作的时候
6、主要操作函数
pthread_rwlock_init(
pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr
);
pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
阻塞:之前对这把锁加的写锁的操作
pthread_rwlock_trydlock(pthread_rwlock_t *rwlock);
加锁成功:0
失败:错误号
pthread_rwlock_wrlock(pthread_rwlock_t *rwlocl);
上一次加锁写锁,还没有解锁的时候
上一次加读锁,没解锁
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
7、练习:
3个线程不定时写同一个全局资源,5个线程不定时读统一全局资源:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//全局变量
int number=0;
//创建读写锁
pthread_rwlock_t lock;
void* write_func(void* arg){
//循环写
while(1)
{
//加写锁
pthread_rwlock_wrlock(&lock);
number++;
printf("== write:%lu,%d\n",pthread_self(),number);
//解锁
pthread_rwlock_unlock(&lock);
usleep(500);
}
return NULL;
}
void* read_func(void* arg){
while(1)
{
//加读锁
pthread_rwlock_rdlock(&lock);
printf("== read:%lu,%d\n",pthread_self(),number);
pthread_rwlock_unlock(&lock);
usleep(500);
}
return NULL;
}
int main(int argc,const char* argv[])
{
pthread_t p[8];
//init 读写锁
pthread_rwlock_init(&lock,NULL);
//创建3个写线程
for(int i=0;i<3;++i){
pthread_create(&p[i],NULL,write_func,NULL);
}
//创建5个读线程
for(int i=3;i<8;++i){
pthread_create(&p[i],NULL,read_func,NULL);
}
//阻塞回收子线程的pcb
for(int i=0;i<8;++i){
pthread_join(p[i],NULL);
}
//释放读写锁资源
pthread_rwlock_destroy(&lock);
return 0;
}
8、读写锁、互斥锁
1、条件变量是锁吗?
不是锁,但是条件变量能够阻塞线程
条件不满足,阻塞线程
当条件满足,通知阻塞的线程开始工作
3、条件变量的类型:pthread_cond_t;
4、主要函数:
pthread_cond_init(
pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr
);
pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_wait(
pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex
);
(1)阻塞线程
(2)将已经上锁的mutex解锁
(3)该函数解除阻塞,会对互斥锁加锁
pthread_cond_timewait(
pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime
);
pthread_cond_signal(pthread_cond_t *restrict cond);
pthread_cond_broadcast(pthread_cond_t *cond);
5、生产者和消费者:
//节点结构
typedef struct node
{
int data;
struct node* next;
}Node;
//永远指向链表头部指针
Node* head=NULL;
//线程同步 - 互斥锁
pthread_mutex_t mutex;
//阻塞线程 - 条件变量类型变量
pthread_cond_t cond;
//生产者
void* producer(void* arg)
{
while(1){
//创建一个链表的节点
Node* pnew=(Node*)malloc(sizeof(Node));
//节点初始化
pnew->data=rand()%1000;//0-999
//使用互斥锁保护共享数据
pthread_mutex_lock(&mutex);
//指针域
pnew->next=head;
head=pnew;
printf("====== produce:%lu,%d\n",pthread_self(),pnew->data);
pthread_mutex_unlock(&mutex);
//通知阻塞的消费者线程,解除阻塞
pthread_cond_signal(&cond);
sleep(rand()%3);
}
return NULL;
}
//消费者
void* customer(void* arg)
{
while(1){
//使用互斥锁保护共享数据
pthread_mutex_lock(&mutex);
//判断链表是否为空
if(head==NULL){
//线程阻塞
//该函数会对互斥锁解锁
pthread_cond_wait(&cond,&mutex);
//解除阻塞之后,对互斥锁做加锁操作
}
//链表不为空,删除一个节点,删除头结点
Node* pdel=head;
head=head->next;
printf("------ customer:%lu,%d\n",pthread_self(),pdel->data);
free(pdel);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(int argc,const char* argv[])
{
pthread_t p1,p2;
//init
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
//创建生产者线程
pthread_create(&p1,NULL,producer,NULL);
//创建消费者线程
pthread_create(&p2,NULL,customer,NULL);
//阻塞回收子线程
pthread_join(p1,NULL);
pthread_join(p2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}