Linux进程通信(3):信号量
来源:互联网 发布:big mac index 编辑:程序博客网 时间:2024/06/15 05:39
一、信号量概述
信号量与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制.相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以
修改该标志.除了用于访问控制外,还可用于进程同步.
信号量有以下两种类型:
二值信号量:最简单的信号量形式,信号量的值只能取0或1,类似于互斥锁
计数信号量:信号量的值可以取任意非负值(当然受内核本身的约束)
注;二值信号量能够实现互斥锁的功能,但两者的关注内容不同.信号量强调共享资源,只要共享资源可用,其他进程同样可以修改信号量的值;互斥锁更强调进程,占用资源的
进程使用完资源后,必须由进程本身来解锁.
二、操作信号量
2.1 创建或者取得信号量
int semget(key_t key, int nsems, int semflg)
参数:key整数值,不相关的进程可以通过它访问同一个信号量
参数;nsems获取的信号量数量,一般为1即可
参数:semflg创建标志,和open的标志类似一般为IPC_CREAT和IPC_EXCL就可以确保得到一个新的唯一的信号量
返回值:返回一个正数,其他信号量操作函数将通过它使用信号量
2.2 信号量操作函数
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:semid为semget的返回值,用来操作分配的信号量
参数:sops信号量操作设置
struct sembuf {
unsigned short sem_num;//操作信号量在整个分配信号量的位置,如果分配一个那么就是0
short sem_op;//信号量操作增量,一般1或者-1
short sem_flg;//信号量标志一般为SEM_UNDO
};
参数:nsops为sops指向数组的大小即分配的信号量的大小
2.3 信号量控制函数
int semctl(int semid,int semnum,int cmd,union semun arg)
参数:semid为semget的返回值,用来操作分配的信号量
参数:semnum操作的信号量在分配的信号量中的位置,分配为1的话,该值为0
参数:cmd操作的选项
SETVAL 设置信号量的初始值,设置
IPC_RMID 删除一个信号量
参数:arg 当cmd为SETVAL时可以设置里面的val变量指定信号量的初始值
union semnum
{
int val;
struct semid_ds *buf;
unsigned short *array;
}
返回值:调用失败返回-1,成功返回与cmd相关
三、应用举例
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include "semun.h"static int set_semvalue(void);static void del_semvalue(void);static int semaphore_p(void);static int semaphore_v(void);static int sem_id;int main(int argc, char **argv){ int i; int pause_time; char op_char = 'O'; srand((unsigned int)getpid()); sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);//获得信号量 if(argc > 1) { if(!set_semvalue())//设置信号量的初始值 { fprintf(stderr, "Failed to initialize semaphore/n"); exit(EXIT_FAILURE); } op_char = 'X'; sleep(2); } for(i=0;i<10;i++) { if(!semaphore_p()) exit(EXIT_FAILURE);//信号量P操作,成功就进入临界区,否则等待其他进程V操作 printf("%c", op_char); fflush(stdout); pause_time = rand() % 3; sleep(pause_time); printf("%c", op_char); fflush(stdout); if(!semaphore_v()) exit(EXIT_FAILURE);//退出临界区前执行V操作 pause_time = rand() % 2; sleep(pause_time); } printf("/n%d - finished/n", getpid()); if(argc > 1) { sleep(10); del_semvalue();//删除信号量 } exit(EXIT_SUCCESS); }static int set_semvalue(void){ union semun sem_union; sem_union.val = 1; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) return 0; return 1;}static void del_semvalue(void){ union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) fprintf(stderr, "Failed to delete semaphore/n");}static int semaphore_p(void){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; sem_b.sem_flag = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_p failed/n"); return 0; } return 1;}static int semaphore_v(void){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; sem_b.sem_flag = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_v failed/n"); return 0; } return 1;}
# ./sem1 1 &
[1] 1082
# ./sem1
OOXXOOXXOOXXOOXXOOXXOOOOXXOOXXOOXXOOXXXX
1083 - finished
1082 - finished
#
正如我们所看到了,O与X是成对出现的,表明临界区部分被正确的处理了。如果这个程序在我们的系统上不能正常运行,也许我们需要在调用程序之前使用命令stty -tostop来保证生成tty输出的后台程序不会引起信号生成。
参考文章:
http://www.cnblogs.com/hjslovewcl/archive/2011/03/03/2314341.html
Linux程序设计第四版
- Linux进程通信(3):信号量
- Linux进程通信--信号量
- Linux进程通信-信号量
- linux进程通信---信号量
- linux进程通信--信号量
- linux进程通信--信号量
- linux进程通信-信号量
- Linux进程通信-信号量
- Linux进程间通信(3):信号量
- Linux进程间通信(3)--信号量
- linux进程通信-信号量使用
- Linux进程通信-使用信号量
- linux进程通信-信号量使用
- linux进程通信-信号量使用
- linux进程通信-信号量使用
- linux进程通信-信号量使用
- Linux进程通信-信号量
- linux进程间通信--信号量
- linux mysql 安装
- Linux进程通信(2):信号(下)
- Linux进程通信(1):管道(上)
- 自己练习做的一些效果图《一》
- 掌握的c语言编程
- Linux进程通信(3):信号量
- 个人工作中常用adb命令记录
- bios 和dos 中断例程
- 一步一步学编程之Python(二)
- VC Debug Assertion Failed File:dlgdata.cpp Line 43
- 自己练习做的一些效果图《二》
- SHChangeNotify
- 自己练习做的一些效果图《三》
- 常用设计模式之MVC模式详解