线程同步:
同步的概念与进程同步的概念一致,让多个线程按照顺序协同执行。为什么线程需要线程同步呢?因为线程很多资源都是共享的,比如全局数据,内存,文件,数据库等等。当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。(同步大多都互斥)
还有一点,因为我们在一个线程中有时候进行的操作并不一定是原子操作,那么如果多个线程同时执行,就有可能会发生线程不安全,进行同步控制后,就可以实现线程安全。
线程同步的机制:
信号量(对临界资源的计数器)
同进程同步相似,线程这里也可以使用信号量来进行同步,但是与进程的还是有些不同
//信号量的创建与初始化,都在一个函数里,同进程的信号量不同
#include<semaphore.h>
int sem_init(sem_t *semid,int shared,unsigned int val);
//失败返回-1,成功返回0
semid:标识操作的信号量,一般是一个全局变量(共享)
shared:控制信号量的类型,指定此信号量是否在进程间共享,如果是0则是当前进程局部的信号量,否则这个信号量可以在多个进程中共享,但是Linux还不支持这种共享,所以一般默认值我们会给0。
val:设置信号量的初始值
//控制信号量的两个函数
#include<semaphore.h>
int sem_wait(sem_t *semid); //相当于p操作,给参数sem指定的信号量值减1,会阻塞
int sem_post(sem_t *Semid); //相当于v操作,给参数sem指定的信号量值加1
//这几个函数都在线程库中封装好了,不用像进程那样自己封装,方便用户调用
在这里说明一点,sem_wait调用的时候,如果信号量不为0则直接给信号量减1继续执行,不会阻塞的,但是如果信号量等于0,调用此函数就会阻塞,等待着其他线程的运行,直到信号零不为0可被调度。但是我们还有一个函数,与sem_wait行使作用一致但是不会阻塞。
#include<semaphore.h>
int sem_trywait(sem_t *semid);
//相当于p操作,给信号零减1,但是不会阻塞
对于信号量的销毁,我们线程库也为用户封装好了,用户可以直接调用
#include<semaphore.h>
int sem_destroy(sem_t *semid); //销毁信号量
信号量同步实例:
//两个线程交替打印
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<pthread.h>
#include<semaphore.h>
sem_t sem; //信号量,设为全局量,使得线程共享
void *fun(void *arg)
{
printf("fun thread start\n");
int i=0;
for(;i<8;i++)
{
sem_wait(&sem);
printf("fun pthread running\n");
sleep(1);
sem_post(&sem);
}
printf("fun pthread end\n");
pthread_exit(NULL);
}
void destory()
{
printf("destory\n");
sem_destroy(&sem);
}
int main()
{
atexit(destory); //注册函数,进程结束会调用它所注册的函数
int n=sem_init(&sem,0,1);
pthread_t id;
int res=pthread_create(&id,NULL,fun,NULL);
assert(res==0);
printf("main pthread start\n");
int i=0;
for(;i<10;i++)
{
sem_wait(&sem);
printf("main pthrea