概念
线程之间共享大量的内容,多线程在访问共享数据时,需要一些保护机制,避免造成数据混乱和错误。
常用互斥技术:互斥锁、信号量
常用同步技术:条件变量
- 互斥锁
编程步骤:
1)初始化互斥锁
2)加锁
3)访问共享资源
4)解锁
5)不再使用,销毁锁
互斥锁实现:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
char *data[5];//长度为5的字符串数组
int size = 0;//记录当前下标,数组中数据个数
//初始化
pthread_mutex_t lock;
//线程函数
void *task(void *arg)
{
//2.加锁
pthread_mutex_lock(&lock);
//3.访问共享内存
data[size] = (char *)arg;
usleep(100000);
size++;
//4.解锁
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
int main()
{
pthread_t id1,id2;
//1.声明
pthread_mutex_init(&lock,NULL);
data[size] = "liubie";
size++;
pthread_create(&id1,NULL,task,"guanyu");
pthread_create(&id2,NULL,task,"zhaoyun");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
int i;
for(i=0;i<size;i++)
printf("%s\n",data[i]);
//5.销毁锁
pthread_mutex_destroy(&lock);
return 0;
}
- 无名信号量
编程步骤:
1)声明信号量
2)初始化信号量的初始计数
3)P操作
4)访问共享资源
5)V操作
6)不再使用,删除信号量
无名信号量实现:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
char *data[5];//长度为5的字符串数组
int size = 0;//记录当前下标,数组中数据个数
//1.声明
sem_t sem;
//线程函数
void *task(void *arg)
{
//3.P操作
sem_wait(&sem);
//4.访问共享内存
data[size] = (char *)arg;
usleep(100000);
size++;
//5.V操作
sem_post(&sem);
pthread_exit(NULL);
}
int main()
{
pthread_t id1,id2;
//2.初始化
sem_init(&sem,0,1);
data[size] = "liubie";
size++;
pthread_create(&id1,NULL,task,"guanyu");
pthread_create(&id2,NULL,task,"zhaoyun");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
int i;
for(i=0;i<size;i++)
printf("%s\n",data[i]);
//6.销毁
sem_destroy(&sem);
return 0;
}
- 有名信号量
编程步骤:
1)声明信号量
2)创建/打开有名信号量
3)P操作
4)访问共享资源
5)V操作
6)不再使用,删除信号量
有名信号量实现
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
char *data[5];//长度为5的字符串数组
int size = 0;//记录当前下标,数组中数据个数
//1.声明信号量
sem_t *sem;
//线程函数
void *task(void *arg)
{
//3.P操作
sem_wait(sem);
//4.访问共享内存
data[size] = (char *)arg;
usleep(100000);
size++;
//5.V操作
sem_post(sem);
pthread_exit(NULL);
}
int main()
{
pthread_t id1,id2;
//2.创建/打开有名信号量
sem = sem_open("mysem",O_RDWR|O_CREAT|O_EXCL,0666,1);
if(sem==SEM_FAILED){
perror("sem_open");
exit(0);
}
data[size] = "liubie";
size++;
pthread_create(&id1,NULL,task,"guanyu");
pthread_create(&id2,NULL,task,"zhaoyun");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
int i;
for(i=0;i<size;i++)
printf("%s\n",data[i]);
//6.销毁
sem_close(sem);
sem_unlink("mysem");
return 0;
}
- 条件变量(同步)
编程接口:
1)声明和初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
或者
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
2)等待条件成立
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
3)唤醒等待条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
4)销毁
int pthread_cond_destroy(pthread_cond_t *cond);
条件变量实现
//条件变量(同步)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
//1.声明
pthread_mutex_t lock;
pthread_cond_t cond;
char buf[100];
void *task1(void *arg)
{
//等待之前先加锁
pthread_mutex_lock(&lock);
printf("线程1加锁成功!\n");
sleep(1);
//2.等待条件成立
pthread_cond_wait(&cond,&lock);
printf("线程1被条件唤醒!\n");
//3.条件成立后执行内容
printf("你的名字的长度为%d\n",strlen(buf));
sleep(10);
//4.条件成立代码执行完解锁
printf("线程1解锁成功!\n");
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
void *task2(void *arg)
{
//等待之前先加锁
pthread_mutex_lock(&lock);
printf("线程2加锁成功!\n");
sleep(1);
//2.等待条件成立
pthread_cond_wait(&cond,&lock);
printf("线程2被条件唤醒!\n");
//3.条件成立后执行内容
printf("靓仔你的名字是%s\n",buf);
sleep(10);
//4.条件成立代码执行完解锁
printf("线程2解锁成功!\n");
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
void *task3(void *arg)
{
sleep(10);
//等待之前先加锁
pthread_mutex_lock(&lock);
printf("线程3加锁成功!\n");
//2.等待条件成立
pthread_cond_wait(&cond,&lock);
printf("线程3被条件唤醒!\n");
//3.条件成立后执行内容
printf("靓仔你名字的第一个字符是%c\n",*buf);
sleep(1);
//4.条件成立代码执行完解锁
printf("线程3解锁成功!\n");
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
int main()
{
pthread_t id1,id2,id3;
//1.初始化
pthread_cond_init(&cond,NULL);
pthread_mutex_init(&lock,NULL);
pthread_create(&id1,NULL,task1,NULL);
pthread_create(&id2,NULL,task2,NULL);
pthread_create(&id3,NULL,task3,NULL);
printf("请输入你的名字:\n");
fgets(buf,100,stdin);
buf[strlen(buf)-1] = 0;
//唤醒等待的线程
//pthread_cond_signal(&cond);//唤醒一个
pthread_cond_broadcast(&cond);//唤醒全部
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_join(id3,NULL);
//5.销毁
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&lock);
return 0;
}