linux进程通信信号实例,Linux进程间通信 --- 信号量(示例代码)

信号量 IPC 原理

信号量通信机制主要用来实现进程间同步,避免并发访问共享资源。信号量可以标识系统可用资源的个数。最简单的信号量为二元信号量

下图为 Linux 信号量通信机制的概念图。在实际应用中,两个进程通信可能会使用多个信号量,因此,Linux 在管理时以信号量集合的概念来管理。

20180207001104837399.png

通常所说的创建一个信号量实际上是创建了一个信号量集合,在这个信号量集合中,可能有多个信号量。整个信号量集合由以下部分组成。

1.信号量集合数据结构:在此数据结构中定义了整个信号量集合的基本属性,如访问权限。

2.信号量:信号量集合使用指针指向一个由数组构成的信号量单元,在此信号量单元中存储了各信号量的值。

信号量集合的数据结构定义如下:

from /usr/include/linux/sem.h

struct semid_ds {

struct ipc_perm sem_perm; /* permissions .. see ipc.h 权限 */

__kernel_time_t sem_otime; /* last semop time 最近semop时间 */

__kernel_time_t sem_ctime; /* last change time 最近修改时间 */

struct sem *sem_base; /* ptr to first semaphore in array 第一个信号量 */

struct sem_queue *sem_pending; /* pending operations to be processed 阻塞信号量 */

struct sem_queue **sem_pending_last; /* last pending operation 最后一个阻塞信号量 */

struct sem_undo *undo; /* undo requests on this array undo队列 */

unsigned short sem_nsems; /* no. of semaphores in array 信号量数 */

};

信号量的数据结构定义如下:

from /usr/src/kernels/xxx/include/linux/sem.h

xxx 为 uname -r 命令所得

struct sem {

int semval; /* current value 信号量的值 */

int sempid; /* pid of last operation 最近一个操作的进程号PID */

};

Linux 信号量管理操作

1.创建信号量集合

#include

#include

#include

/*

* 第一个参数为 key 值,一般由 ftok() 函数产生

* 第二个参数为创建的信号量个数,以数组的方式存储

* 第三个参数用来标识信号量集合的权限

*/

int semget(key_t key, int nsems, int semflg);

2.控制信号量集合、信号量

#include

#include

#include

/*

* 第一个参数为要操作的信号量标识符

* 第二个参数,如果要操作的是信号量则它是信号量的下标;如果操作集合,此参数无意义

* 第三个参数为要执行的操作

* 第四个参数则需根据第三个参数进行设置,其类型为 senum 的共用体

*/

int semctl(int semid, int semnum, int cmd, ...);

semun 共用体如下:

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO

(Linux-specific) */

};

3.信号量的操作

#include

#include

#include

/*

* 第一个参数为要操作的信号量的标识符

* 第二个参数为 sembuf 结构体

* 第三个参数为 sops 个数

*/

int semop(int semid, struct sembuf *sops, unsigned nsops);

sembuf 结构体如下:

struct sembuf {

unsigned short sem_num; /* semaphore index in array 信号量下标 */

short sem_op; /* semaphore operation 信号量操作 */

short sem_flg; /* operation flags 操作标识 */

};

sem_flg 为操作标识。可选为以下各值:

IPC_NOWAIT:在对信号量集合的操作不能执行的情况下,调用立即返回。

SEM_UNDO:当进程退出后,该进程对 sem 进行的操作将被撤销。

程序实例

下面用一个程序来演示 SEM_UNDO 的效果:

#include

#include

#include

#include

#include

#include

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO */

};

static void sem_init(int id)

{

union semun sem;

sem.val = 10;

/* 初始化信号量的值 */

semctl(id, 0, SETVAL, sem);

}

static void sem_v(int id)

{

struct sembuf buf = {

.sem_num = 0,

.sem_op = -1,

/* 可改为 SEM_UNDO 查看结果 */

// .sem_flg = 0,

.sem_flg = SEM_UNDO,

};

/* 操作信号量 */

semop(id, &buf, 1);

}

static int get_val(int id)

{

/* 获取信号量的值 */

return semctl(id, 0, GETVAL);

}

int main()

{

int sem_id, pid;

/* 创建信号量集合 */

sem_id = semget((key_t)1004, 1, IPC_CREAT | 0600);

sem_init(sem_id);

if((pid = fork()) == -1){

perror("fork Err");

exit(0);

}

else if(!pid){

sem_v(sem_id);

printf("child : %d \n", get_val(sem_id));

}

else{

sleep(1);

printf("parent : %d \n", get_val(sem_id));

}

return 0;

}

如果未采用 SEM_UNDO 标识,子进程输出 9 ,父进程输出 9;

如果采用了 SEM_UNDO 标识,子进程输出 9,父进程输出 10。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值