加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Linux进程通信之信号量机制

(2017-06-29 09:57:15)
标签:

linux应用程序

分类: Linux应用程序编程

1. 原由:

由于Linux是一个多任务操作系统,所以存在多个任务同时访问一个资源的问题,但是有些资源在同一时间只能有一个进程访问,例如打印机或者一些全局变量等,这些资源称为临界资源,访问临界资源的代码称为临界区,这种行为称为多进程之间的竟态,为解决这一问题,Linux提供了信号量机制,用于同步各个进程有序访问临界区。

2. Linux信号量:

Linux信号量有三类,第一类内核信号量,用于内核进程之间的同步,这个暂时不管。第二类继承于POSIX信号量机制,这个主要用于Linux线程同步,暂时也不管;第三类是继承于System V信号量机制,主要用于Linux进程间同步,这也是目前Linux系统应用程序进程同步所使用的,本文先介绍这种。

3. 进程间通信方式:

在创建一个信号量集的时候,内核会自动会信号量集分配一个IPC标识符,然后不同进程间通过IPC标识符操作信号量集,以此实现同步。但是IPC标识符是系统随机分配的,所以需要引入key,即系统根据key值生成IPC标识符,如果key值一致标识符也一致。关于key值的设置方式有三种:

1)服务器进程通过IPC_PRIVATE键值,生成IPC标识符之后,把标识符存入文件,客户端进程从文件读出标识符,进行通信;此方法也可以用在父子进程通信,在此情形下不需要文件作为中介,因为子进程继承了父进程的IPC标识符,可以直接通信。缺点:文件中介,代价高,使用不方便。

2)在一个共有头文件定义键值,然后需要通信的进程都包含这个头文件,然后直接通信。缺点:必须检测该键值是否已经使用,必须处理已经使用的情况。

3)使用ftok()函数,通过指定文件和一个指定值生成键值,缺点若文件删除又重建,则此方式失效。

这三类方法,个人感觉各有优劣,需要针对实际选用。值得说明的是,后续消息队列和共享内存,都是使用这种方式完成进程间通信的。信号量是一种进程间控制信息,而消息队列和共享内存是进程间数据消息。

4. 底层支持:

System V信号机制在内核层,使用三个如下数据结构管理信号量:

struct semid_ds {
struct ipc_perm sem_perm;
struct sem *sem_base;
ushort sem_nsems;
time_t sem_otime;
time_t sem_ctime;
};

struct sem {
ushort semval;
short sempid;
ushort semncnt;
ushort semzcnt;
};

struct sembuf {
short sem_num; // 要操作的信号量在信号量集里的编号,
short sem_op; // 信号量操作1-->v, -1--->p
short sem_flg; // 操作表示符,信号量释放时机
};

System V中是以信号量集为单位管理信号量的,每个信号量集用一个struct semid_ds结构描述,其中的sem_base是一个结构数组,每个元素既是一个信号量,每个信号量用struct sem结构描述。一个struct sembuf 结构代表一个信号量操作。

5. 应用层使用:

(1)创建信号量集:

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

输入:参数key:键值。

  参数nsems:信号量个数。

      参数semflg:信号量集操作权限。

输出:返回值信号量集id(ipc的标识符,semid),用于后续进程通信使用。

此函数在系统内部,即创建了一个struct semid_ds,并设置部分元素的值,此结构包含struct sem结构。

(2)设置信号量初值(赋值):

int semctl(int senid, int semnum, int cmd, union semun arg)

输入:参数senid:信号量集id,semget函数返回值。

  参数semnum:信号量在信号量集中的序号,如果是一个信号量,此值设为0.

  参数cmd:对信号量得操作命令。赋值,使用IPC_SETVAL指令。

  参数arg:根据cmd的不同,作用不同。

输出:返回值表示设置是否成功。

  Semid:带有信号量初值的信号量集。即设置了semid_ds-->sem-->semval = arg.val。

(3)信号量操作:

Int semop(int semid, struct sembuf *sops, size_t nsops)

输入:参数senid:信号量集id,semget函数返回值。

  参数sops:信号量操作数组。具体见第四段的struct sembuf

  参数nsops:带操作的信号量在信号量集数组中的下标。

输出:semid,执行p或v之后信号量。

(4)删除信号量:

使用semctl函数,组合IPC_RMID即可。

6. 说明:

在上述函数中,本质上,应用层的接口是semid,内核层的支持即为第四步中的三大结构,尤其是前两个。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有