本帖最后由 yuanlai2010 于 2014-9-12 08:55 编辑
POSIX线程同步篇1
用信号量进行同步
参与Helper2416开发板助学计划心得
什么是信号量
在前面的帖子中有提到SystemV IPC机制的信号量,不过那主要时用于进程间的同步的,而现在用于线程的信号量是取自POSIX的实时扩展。
信号量是一个特殊类型的变量,它可以被增加或减少,但对其的关键访问被保证时原子操作,即使在一个多线程程序中也时如此。这意味着如果一个程序中有两个或更多的线程试图改变一个信号量的值,系统将保证所有的操作都将依次进行。
原子操作是指,如果两个线程企图同时给一个信号量加1,他们之间不会相互干扰,而不像如果两个程序同时对同一个文件进行读取、增加、写入操作时可能会引起冲突。
信号量一般用来保护一段代码,使其每次只能被一个执行线程运行,要完成这个工作,可以使用二进制信号量——它只有0和1两种取值。有时候还需要使用到通用信号量,它具有更大的取值范围。两者实际调用的函数都是一样的,根据需求给定参数就OK了。
POSIX信号量函数
信号量函数的名字都以sem_开头,线程中使用的基本信号量函数有如下4个。
#include
intsem_init(sem_t *sem, int pshared, unsigned int value);
intsem_wait(sem_t *sem);
intsem_post(sem_t *sem);
intsem_destroy(sem_t * sem);
sem_init
函数原型:intsem_init(sem_t *sem, int pshared, unsigned int value);
函数功能:初始化信号量。
函数返回:调用成功返回0。
参数说明:
第一个参数sem_t*sem,指定信号量对象。
第二个参数intpshared,控制信号量的类型(共享选项),如果其值为0,就表示这个信号量是当前进程的局部信号量,否则,这个信号量就可以在多个进程之间共享。
第三个参数unsignedint value,给定信号量一个出世的整数值。
sem_wait
函数原型:intsem_wait(sem_t *sem);
函数功能:以原子操作的方式将信号量的值减1,但它会等待直到信号量有个非零值才会开始减法操作。
函数返回:调用成功返回0。
参数说明:sem_t*sem指向由sem_init初始化的信号量。
sem_post
函数原型:intsem_post(sem_t*sem);
函数功能:以原子操作的方式将信号量的值加1。
函数返回:调用成功返回0。
参数说明:sem_t*sem指向由sem_init初始化的信号量。
sem_destroy
函数原型:intsem_destroy(sem_t*sem);
函数功能:用完信号量后对它进行清理。
函数返回:调用成功返回0。
参数说明:sem_t*sem指向由sem_init初始化的信号量。该函数清理该信号量拥有的所有资源,如果企图清理的信号量正被一些线程等待,就会收到一个错误。
代码实践
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <semaphore.h>
- void *pthread1(void *arg);
- void *pthread2(void *arg);
- sem_t thread_sem;
- int main()
- {
- pthread_t thread_id1,thread_id2;
- void *thread_result1, *thread_result2;
- int res;
-
- res = sem_init(&thread_sem,0,1);
- if(res != 0){
- perror("semaphore initialization failed ...\n");
- exit(EXIT_FAILURE);
- }
-
- res = pthread_create(&thread_id1,NULL,pthread1,NULL);
- if(res != 0){
- perror("pthread1 is not created ...\n");
- exit(EXIT_FAILURE);
- }
- res = pthread_create(&thread_id2,NULL,pthread2,NULL);
- if(res != 0){
- perror("pthread2 is not created ...\n");
- exit(EXIT_FAILURE);
- }
- res = pthread_join(thread_id1,&thread_result1);
- if(res != 0){
- perror("pthread1 join failed ...\n");
- exit(EXIT_FAILURE);
- }
- res = pthread_join(thread_id2,&thread_result2);
- if(res != 0){
- perror("pthread2 join failed ...\n");
- exit(EXIT_FAILURE);
- }
-
- printf("the pthread1 return %s\n",(char *)thread_result1);
- printf("the pthread2 return %s\n",(char *)thread_result2);
- sem_destroy(&thread_sem);
- return 0;
- }
- void *pthread1(void *arg)
- {
- int i;
- for(i=0;i<10;i++){
- sem_wait(&thread_sem);
- printf("hello this is pthread1 --> %d\n",i);
- sem_post(&thread_sem);
- sleep(2);
- }
- pthread_exit("pthread1 finished ...\n");
- }
- void *pthread2(void *arg)
- {
- int i;
- for(i=0;i<10;i++){
- sem_wait(&thread_sem);
- printf("hello this is pthread2 --> %d\n",i);
- sem_post(&thread_sem);
- sleep(2);
- }
- pthread_exit("pthread2 finished ...\n");
- }
复制代码
运行结果
- [yuanlai@fedora pthread]$ gcc -D_REENTRANT pthread1.c -o pthread1 -lpthread
- [yuanlai@fedora pthread]$ ./pthread1
- hello this is pthread1 --> 0
- hello this is pthread2 --> 0
- hello this is pthread1 --> 1
- hello this is pthread2 --> 1
- hello this is pthread1 --> 2
- hello this is pthread2 --> 2
- hello this is pthread1 --> 3
- hello this is pthread2 --> 3
- hello this is pthread1 --> 4
- hello this is pthread2 --> 4
- hello this is pthread1 --> 5
- hello this is pthread2 --> 5
- hello this is pthread1 --> 6
- hello this is pthread2 --> 6
- hello this is pthread1 --> 7
- hello this is pthread2 --> 7
- hello this is pthread1 --> 8
- hello this is pthread2 --> 8
- hello this is pthread1 --> 9
- hello this is pthread2 --> 9
- the pthread1 return pthread1 finished ...
- the pthread2 return pthread2 finished ...
- [yuanlai@fedora pthread]$
复制代码
从运行结果来看,是按照同时运行的规律来打印出信息的,通过信号量来确保同一时刻只有一个线程在打印信息,但是再回头看上一篇的实践代码的时候,发现,即使没用信号量,打印出来的结果还是正常的,就算不使用sleep调用也是正常的,结果显示,虽然我的笔记本是双核四线程的CPU,但是thread1和thread2还是和运行在单核单线程处理器上一样。还得继续去探究这里面的奥秘。
论坛ID:yuanlai2010
发表时间:2014-09-12