今天来谈谈线程的同步--信号量。
首先来看看一些概念性的东西:
如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。
在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。
线程同步的方式和机制
临界区、互斥量、事件、信号量四种方式
临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作
这里我们重点讨论下信号量。
- int sem_init(sem_t *sem, int pshared, unsigned int value);,其中sem是要初始化的信号量,为0时表示只能在当前进程的多个线程之间共享,pshared表示此信号量是在进程间共享还是线程间共享,value是信号量的初始值。
- int sem_destroy(sem_t *sem);,其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
- int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
- int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。
上代码:
/*
线程信号量测试用例
*/
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
sem_t sem;
int running = 1;
void * producter_f(void *arg)
{
int semval = 0;
while(running)
{
usleep(1);
sem_post(&sem);
sem_getvalue(&sem,&semval);
printf("生产,总数量:%d\n",semval);
}
}
void * consumer_f(void *arg)
{
int semval = 0;
while(running)
{
usleep(1);
sem_wait(&sem);
sem_getvalue(&sem,&semval);
printf("消费,总数量:%d\n",semval);
}
}
int main()
{
pthread_t consumer_t;
pthread_t producter_t;
int err;
sem_init(&sem,0,16);
err = pthread_create(&producter_t,NULL,(void *)producter_f,NULL);
printf("%d",err);
pthread_create(&consumer_t,NULL,(void *)consumer_f,NULL);
sleep(1);
running = 0;
pthread_join(producter_t,NULL);
pthread_join(consumer_t,NULL);
sem_destroy(&sem);
return 0;
}