线程之间的资源是共享的
一、互斥锁
(一)逻辑
不让线程自己私自访问共享资源
在访问共享资源之前先判断是否有人在使用,有人使用则先等待,否则就使用
(二)代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int count = 100;
pthread_mutex_t mutex; //诞生一把全局锁
void *new_thread(void *arg)
{
pthread_mutex_lock(&mutex); //上锁
printf("线程上锁成功\n");
if(count >= 100)
{
sleep(1);
count -= 100;
}
pthread_mutex_unlock(&mutex); //解锁
printf("线程解锁成功\n");
return NULL;
}
int main(void)
{
pthread_t tid; //创建线程
int retval;
pthread_mutex_init(&metex, NULL); //初始化互斥锁
retval = pthread_creat(&tid, NULL, new_thread, NULL);
if(retval != 0)
{
fprintf(stderr, "创建线程失败:%s\n", strerror(retval));
return -1;
}
pthread_mutex_lock(&metex); //上锁
printf("主线程上锁成功\n");
if(count >= 100)
{
sleep(1);
count -=100;
}
pthread_mutex_unlock(&metex); //解锁
printf("主线程解锁成功\n");
pthread_join(tid, NULL); //等待子线程介绍
pthread_mutex_destroy(&mutex); //销毁互斥锁
printf("count = %d\n", count);
return 0;
}
二、读写锁
(一)特点
可以A、B一起读取,但不可以A一边读、B一边写,也不可以A一边写、B也在一边写,即只要碰到写操作就会变成互斥锁
(二)代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int count = 100;
pthread_rwlock_t rwlock; //诞生一把全局读写锁
void *read_thread(void *arg)
{
int i = 5;pthread_rwlock_rdlock(&rwlock); //读锁
while(i--)
{
sleep(1);printf("读线程:%s, count = %d\n", (char *)arg, count += 100);
}
pthread_rwlock_unlock(&rwlock); //解锁
}
void *write_thread(void *arg)
{
int i = 5;pthread_rwlock_wrlock(&rwlock); //写锁
while(i--)
{
sleep(1);
printf("写线程:%s, count = %d\n", (char *)arg, count += 100);
}
pthread_rwlock_unlock(&rwlock); //解锁
}
int main(void)
{
pthread_t tid[2]; //创建读、写线程int retval;
pthread_rwlock_init(&rwlock, NULL); //初始化读写锁
retval = pthread_create(tid, NULL, read_thread, "NO.1");
if(retval != 0)
{
fprintf(stderr, "创建读线程失败:%s\n", strerror(retval));return -1;
}
retval = pthread_create(tid + 1, NULL, write_thread, "NO.2");
if(retval != 0)
{
fprintf(stderr, "创建写线程失败:%s\n", strerror(retval));
return -1;
}
pthread_join(tid[0], NULL); //等待读线程结束
pthread_join(tid[1], NULL); //等待写线程结束
pthread_rwlock_destroy(&rwlock); //销毁读写锁
return 0;
}
三、条件变量
(一)使用规则
必须配合互斥锁使用,是阻塞等待机制,若不符合判断条件就先休眠等待,反之则唤醒执行
(二)代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
int count=1000;
pthread_mutex_t mutex; //诞生一把全局锁
pthread_cond_t cond; //诞生一个条件变量
void *new_thread(void *arg)
{
int retval;
while(1)
{
pthread_mutex_lock(&mutex); //拿锁
printf("%s线程拿锁成功\n", (char *)arg);
while(count <100)
{
printf("线程%s开始睡眠\n", (char *)arg);
//解锁,等待被唤醒,被唤醒后再去拿锁
pthread_cond_wait(&cond, &mutex);
printf("线程%s醒来\n", (char *)arg);
}
count -= 100;
sleep(1);
printf("%s线程还锁成功,余额=%d\n", (char *)arg, count);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
void sighand(int signum)
{
pthread_mutex_lock(&mutex);
printf("充值\n");
count+=1000;
pthread_mutex_unlock(&mutex);
//pthread_cond_signal(&cond); //唤醒一条线程
pthread_cond_broadcast(&cond); //唤醒所有因指定条件变量睡眠的线程
}
int main(void)
{
pthread_t tid[3];
int retval;
pthread_mutex_init(&mutex, NULL); //初始化互斥锁
pthread_cond_init(&cond, NULL); //初始化条件变量
retval = pthread_create(tid, NULL, new_thread, "1");
if(retval != 0)
{
fprintf(stderr, "创建线程失败:%s\n", strerror(retval));
return -1;
}
retval = pthread_create(tid+1, NULL, new_thread, "2");
if(retval != 0)
{
fprintf(stderr, "创建线程失败:%s\n", strerror(retval));
return -1;
}
retval = pthread_create(tid+2, NULL, new_thread, "3");
if(retval != 0)
{
fprintf(stderr, "创建线程失败:%s\n", strerror(retval));
return -1;
}
signal(SIGINT, sighand);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
pthread_cond_destroy(&cond); //销毁条件变量
pthread_mutex_destroy(&mutex); //销毁互斥锁
printf("count=%d\n", count);
return 0;
}
(三)适用场景
需要线程等待某个条件符合才去运行,否则就休眠
四、信号量(匿名)
(一)作用
访问一个进程中的某块资源,判断是否存在这块资源
(二)常用函数
sem_init 初始化信号量
sem_wait P操作(减)
sem_post V操作(加)
sem_destroy 销毁信号量
(三)代码
#include <stdio.h>
#include <string.h>
#inlcude <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem; //信号量
char buffer[100]; //缓冲区
void *new_thread(void *arg)
{
while(1)
{
fgets(buffer, sizeof(buffer), stdin); //从键盘中读入一行数据到 buffer 中
sem_post(&sem); //V操作
}
return NULL;
}
int main(void)
{
pthread_t tid;
int retval;
sem_init(&sem, 0, 0);
retval = pthread_create(&tid, NULL, new_thread, "faye");
if(retval != 0)
{
fprintf(stderr, "创建线程失败:%s\n", strerror(retval));
return -1;
}
while(1)
{
sem_wait(&sem); //P操作
printf("buffer = %s\n", buffer);
}
pthread_join(tid, NULL);
sem_destroy(&sem); //销毁信号量
return 0;
}