linux多线程----信号量
2014-02-24 11:47
162 查看
信号量:信号量是操作系统中所用到的PV原子操作,他广泛用于进程与线程的同步与互斥,信号量本质是一个非负的整数计数器,被用来控制对公共资源的访问,下面是pv操作的工作原理:
PV原子操作是对整数计数器信号量sem的操作,一次p操作使sem减1,一次v操作使sem加1,进程或者线程根据信号量判断是否对公共资源具有访问权限,当信号量sem的值大于等于0时,则进程或线程具有公共资源的访问权,当信号量小于0时,则进程或线程会被阻塞,直到信号量sem大于等于0为止
信号值的含义:
如果信号量的值大于0表示可用的资源数,小于0表示阻塞的进程数
p操作:
将信号量减一后,如果>=0,则表示有可用的资源,线程继续执行
信号量减一后,如果<0,则线程会被阻塞,放在阻塞队列中
v操作:
将信号量加一后,如果大于0表示没有阻塞的线程
将信号量加一后,如果小于0或者等于0,说明之前s<0表示有线程在等待队列中,从等待队列中取出一个线程执行。
pv操作必须成对的使用
pv操作主要用于进程或线程的同步和互斥两种情况,如果用于互斥,只需设置一个信号量sem,其流程图如下:
当信号量用于同步操作时,通常需要设置多个信号量,并安排不同的初始值来实现他们的之间的执行顺序,其流程如下:
linux实现了POSIX的无名信号量,主要用于线程间的互斥与同步,这里主要介绍了几个函数:
sem_init()用于创建一个信号量,并初始化他的值
sem_wait()和sem_trywait()都相当于P操作,当信号量大于0时他们都会将信号量减一,两者的区别是当信号量小于0时,sem_wait()会阻塞进程,而sem_trywait()会立即返回
sem_post()相当于V操作,他将信号量的值加1同时发出信号来唤醒等待的进程
sem_getvalue()用于得到信号量的值
sem_destroy()用于删除信号量
sem_init()函数格式如下:
sem_wait()函数语法如下:
下面这个例子通过信号量实现三个线程有序的执行,按照创创建的相反顺序执行:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_NUMBER 3//线程个数
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0
void *thrd_func(void *arg)//线程函数
{
int thrd_num = (int)arg ;
int delay_time = 0 ;
int count = 0 ;
sem_wait(&sem[thrd_num]) ;//执行P操作,信号量的值减一
printf("thread %d is starting\n", thrd_num) ;
for (count = 0; count < REPEAT_NUMBER; count++)//每个线程完成五次任务
{
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;//产生随机时间
sleep(delay_time) ;
printf("\tThread %d:job %d delay = %d\n",
thrd_num, count, delay_time) ;
}
printf("thread %d finished\n", thrd_num) ;
pthread_exit(NULL) ;
}
int main()
{
pthread_t thread[THREAD_NUMBER] ;
int no = 0, res ;
void *thrd_ret ;
srand(time(NULL)) ;//产生随机种子
pthread_mutex_init(&mutex, NULL ) ;//初始化互斥锁,默认的是快速互斥锁
for(no = 0; no < THREAD_NUMBER; no++)
{
sem_init(&sem[no], 0, 0) ;//初始化信号量,将其值设为0
res = pthread_create(&thread[no], NULL, thrd_func, (void *)no) ;//创建线程
if (res != 0)
{
printf("create thread %d failed\n", no) ;
exit(res) ;
}
}
printf("create threads success\n waiting for threads to finish...\n") ;
sem_post(&sem[THREAD_NUMBER - 1]) ;//对最后一个信号量执行V操作
for (no = THREAD_NUMBER - 1; no >= 0; no--)
{
res = pthread_join(thread[no], &thrd_ret) ;
if (!res)
{
printf("thread %d joined\n", no) ;
}
else
{
printf("thread %d joined failed", no) ;
}
sem_post(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]) ;//对相应的信号量执行V操作
}
for (no = 0; no < THREAD_NUMBER; no++)
{
sem_destroy(&sem[no]) ;//销毁信号量
}
exit(0) ;
}
其原理就是利用pv操作来进行线程的控制,首先三个线程都被阻塞住了,然后对第三个信号量执行V操作,依次向上,这样线程就从创建的反方向执行了,其结果如下:
可以明显看出信号量控制了线程的执行顺序。
PV原子操作是对整数计数器信号量sem的操作,一次p操作使sem减1,一次v操作使sem加1,进程或者线程根据信号量判断是否对公共资源具有访问权限,当信号量sem的值大于等于0时,则进程或线程具有公共资源的访问权,当信号量小于0时,则进程或线程会被阻塞,直到信号量sem大于等于0为止
信号值的含义:
如果信号量的值大于0表示可用的资源数,小于0表示阻塞的进程数
p操作:
将信号量减一后,如果>=0,则表示有可用的资源,线程继续执行
信号量减一后,如果<0,则线程会被阻塞,放在阻塞队列中
v操作:
将信号量加一后,如果大于0表示没有阻塞的线程
将信号量加一后,如果小于0或者等于0,说明之前s<0表示有线程在等待队列中,从等待队列中取出一个线程执行。
pv操作必须成对的使用
pv操作主要用于进程或线程的同步和互斥两种情况,如果用于互斥,只需设置一个信号量sem,其流程图如下:
当信号量用于同步操作时,通常需要设置多个信号量,并安排不同的初始值来实现他们的之间的执行顺序,其流程如下:
linux实现了POSIX的无名信号量,主要用于线程间的互斥与同步,这里主要介绍了几个函数:
sem_init()用于创建一个信号量,并初始化他的值
sem_wait()和sem_trywait()都相当于P操作,当信号量大于0时他们都会将信号量减一,两者的区别是当信号量小于0时,sem_wait()会阻塞进程,而sem_trywait()会立即返回
sem_post()相当于V操作,他将信号量的值加1同时发出信号来唤醒等待的进程
sem_getvalue()用于得到信号量的值
sem_destroy()用于删除信号量
sem_init()函数格式如下:
sem_wait()函数语法如下:
下面这个例子通过信号量实现三个线程有序的执行,按照创创建的相反顺序执行:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_NUMBER 3//线程个数
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0
void *thrd_func(void *arg)//线程函数
{
int thrd_num = (int)arg ;
int delay_time = 0 ;
int count = 0 ;
sem_wait(&sem[thrd_num]) ;//执行P操作,信号量的值减一
printf("thread %d is starting\n", thrd_num) ;
for (count = 0; count < REPEAT_NUMBER; count++)//每个线程完成五次任务
{
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;//产生随机时间
sleep(delay_time) ;
printf("\tThread %d:job %d delay = %d\n",
thrd_num, count, delay_time) ;
}
printf("thread %d finished\n", thrd_num) ;
pthread_exit(NULL) ;
}
int main()
{
pthread_t thread[THREAD_NUMBER] ;
int no = 0, res ;
void *thrd_ret ;
srand(time(NULL)) ;//产生随机种子
pthread_mutex_init(&mutex, NULL ) ;//初始化互斥锁,默认的是快速互斥锁
for(no = 0; no < THREAD_NUMBER; no++)
{
sem_init(&sem[no], 0, 0) ;//初始化信号量,将其值设为0
res = pthread_create(&thread[no], NULL, thrd_func, (void *)no) ;//创建线程
if (res != 0)
{
printf("create thread %d failed\n", no) ;
exit(res) ;
}
}
printf("create threads success\n waiting for threads to finish...\n") ;
sem_post(&sem[THREAD_NUMBER - 1]) ;//对最后一个信号量执行V操作
for (no = THREAD_NUMBER - 1; no >= 0; no--)
{
res = pthread_join(thread[no], &thrd_ret) ;
if (!res)
{
printf("thread %d joined\n", no) ;
}
else
{
printf("thread %d joined failed", no) ;
}
sem_post(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]) ;//对相应的信号量执行V操作
}
for (no = 0; no < THREAD_NUMBER; no++)
{
sem_destroy(&sem[no]) ;//销毁信号量
}
exit(0) ;
}
其原理就是利用pv操作来进行线程的控制,首先三个线程都被阻塞住了,然后对第三个信号量执行V操作,依次向上,这样线程就从创建的反方向执行了,其结果如下:
可以明显看出信号量控制了线程的执行顺序。
相关文章推荐
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
- Linux多线程——使用信号量同步线程
- linux多线程学习(六)——信号量实现同步
- linux多线程编程详解教程(线程通过信号量实现通信代码)
- Linux多线程--使用信号量同步线程【转】
- linux多线程编程详解教程(线程通过信号量实现通信代码)
- linux多线程学习(五)——信号量线程控制
- linux多线程学习(六)——信号量实现同步
- Linux多线程编程-信号量
- linux多线程编程--信号量和条件变量 唤醒丢失事件
- linux多线程简单介绍-线程创建、终止、属性设置、多线程同步技术(互斥量、条件变量、信号量)
- linux多线程学习(五)——信号量线程控制
- Linux多线程——使用信号量同步线程
- linux多线程学习(五)——信号量线程控制
- linux多线程变成第四篇--信号量
- Linux多线程——使用信号量同步线程
- Linux多线程——使用信号量同步线程
- linux多线程之信号量---疯狂打印abcd
- linux多线程学习(五)——信号量线程控制
- linux多线程【8】mmap实现父子进程的共享内存通信,用信号量同步