在之前的学习过程中,学习了进程同步。那么何谓同步?
同步:多进程或者多线程访问临界资源时,必须进行同步控制。现在有一个临界资源,进程A向临界资源中写入数据,进程B从临界资源中读取数据。如果进程A中没有数据,那么进程B就无法读取,当然,在进程B读取数据的过程中,进程A就无法再向其中写入数据。这个过程就需要同步控制。多进程或者多线程的执行也并不是完全的并行运行,有的时候主线程的执行需要等待函数线程的某些条件的发生。
之前学习进程间数据共享的时候,知道父子进程间除了共享文件描述符之外,全局数据、堆区数据和栈区数据都是不共享的。但是线程不一样,多线程之间除了栈区数据不共享之外,包括全局数据、堆区数据和文件相关数据都是共享的。
多线程之间也有很多的临界资源,那么如何实现多线程的同步呢?今天就给大家介绍两种线程间的同步控制方式。
一、信号量
头文件:#include <semaphore.h>
1、获取信号量
函数原型:int sem_init(sem_t *sem,int shared,int value) 返回值:成功返回0,失败返回-1
参数意义:sem:是一个sem_t类型的指针,指向信号量的对象
shared:能否在多进程中共享数据。linux中不支持,所以一般设置成0
value:信号量的初始值
2、p操作
函数原型:int sem_wait(sem_t *sem)
3、v操作
函数原型:int sem_post(sem_t *sem)
4、删除
函数原型:int sem_destroy(sem_t *sem)
5、示例
用信号量实现主线程循环获取用户输入,函数线程统计用户输入的字符个数(统计一次需要5秒)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <pthread.h>
#include <semaphore.h>
char buff[128]={0};
sem_t sem;
void *char_count()//函数线程
{
while(1)
{
sem_wait(&sem);//p操作
if(strncmp(buff,"ok",2)==0)
{
break;
}
sleep(5);
printf("count=%d\n",strlen(buff));
}
pthread_exit(NULL);
}
void main()
{
pthread_t id;
int res=pthread_create(&id,NULL,char_count,NULL);
assert(res==0);
sem_init(&sem,0,0);//初始化
printf("please input:");
while(1)
{
fgets(buff,127,stdin);
buff[strlen(buff)-1]=0;
sem_post(&sem);//V操作
if(strncmp(buff,"ok",2)==0)
{
exit(0);
}
}
pthread_exit(NULL);
}
运行结果:
当第一次输入的数据被读取之后,再接着输入,结果会很正确的被统计。但是如果第一次输入的数据尚未被统计,接着输入的话,结果就会出错
当第一次输入的数据尚未被统计,再接着输入的话,结果就会出错。如下图所示。那么就无法真正地实现同步。说明用信号量解决多线程同步依旧有弊端,所以又有了另一种同步机制—互斥锁。
二、互斥锁
1、互斥锁的概念
互斥锁就如生活中的锁一样,当上锁以后,无法在进去或者出来,只有等到解锁以后,才可以接着访问。互斥锁就是这样,使用它可以实现对临界资源的完全控制。当一个线程完成加锁操作以后,表示现在这个资源是该线程占有,其他的线程没有办法再进行加锁操作,也就意味着无法对临界资源实现访问,只有等到解锁操作以后。
2、初始化操作
函数原型:int pthread_mutex_init(pthread_mutex_t *mutex,pthread_mutex_t *attr)
3、加锁操作
函数原型:int pthread_mutex_lock(pthread_mutex_t *mutex)
4、解锁操作
函数原型:int pthread_mutex_unlock(pthread_mutex_t *mutex)
5、释放
函数原型:int pthread_mutex_destroy(pthread_mutex_t *mutex)
6、示例
和上面信号量的例子一样,要求用互斥锁实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <pthread.h>
#include <semaphore.h>
char buff[128]={0};
pthread_mutex_t mutex;
void *char_count()
{
while(1)
{
pthread_mutex_lock(&mutex);
if(strncmp(buff,"ok",2)==0)
{
break;
}
printf("count=%d\n",strlen(buff));
pthread_mutex_unlock(&mutex);
sleep(1);
}
pthread_exit(NULL);
}
void main()
{
pthread_t id;
pthread_mutex_init(&mutex,NULL);//chu shi hua hu chi suo
int res=pthread_create(&id,NULL,char_count,NULL);
assert(res==0);
printf("please input:\n");
while(1)
{
pthread_mutex_lock(&mutex);
fgets(buff,127,stdin);
buff[strlen(buff)-1]=0;
pthread_mutex_unlock(&mutex);
if(strncmp(buff,"ok",2)==0)
{
exit(0);
}
sleep(1);
}
pthread_exit(NULL);
}
运行结果: