信号量

信号量:信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对于临界资源访问的同步。临界资源可以

理解为在某一时刻只能由一个进程或线程操作的资源,这里的资源可以是一段代码、一个变量或某种硬件资源。信号量的

值大于或等于0时表示可供并发进程使用的资源实体数,小于0时表示正在等待使用临界资源的进程数。

Linux内核也为每个信号集维护了一个semid_ds数据结构实例,该结构定义在头文件linux/sem.h中,各个字段含义为:

struct semid_ds
{
struct ipc_perm sem_perm; //对信号进行操作的许可权
__kernel_time_t sem_otime; //对信号进行操作的最后时间
__kernel_time_t em_ctime; //对信号进行修改的最后时间
struct sem *sembase; //指向第一个信号
struct sem_queue sem_pending; //等待处理的挂起操作
struct sem_queue **sem_pending_last; //最后一个正在挂起的操作
struct sem_undo *undo; //撤销的请求
ushort sem_nsems; //数组中的信号数
};

信号量使用key_t值作为它的名字。头文件<sys/types.h>把key_t这个数据类型定义为一个整数,它通常是一个至少32位

的整数。这些整数值通常由ftok函数赋予的。函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为

IPC键。该函数原形为:

#include <sys/ipc.h>

key_t ftok(const char *pathname,int proj_id);

创建或打开信号量前需要使用ftok函数得到key值,下面是ftok函数的包裹函数:

key_t Ftok(const char *pathname,int proj_id)
{
key_t key= ftok(pathname,proj_id);
if(key== -)
{
perror("ftok.");
exit();
}
return key;
}

信号量的创建或打开:

Linux下使用系统函数semget函数创建或打开信号量。该函数定义在头文件<sys/sem.h>中,该函数的原形为:

#include <sys/ipc.h>
   #include <sys/sem.h>
   int semget(key_t key,int nsems,int semflg);

该函数执行成功返回一个信号量的标示符,失败返回-1。函数的第一个参数为ftok()函数得到的键值,第二个参数nsems

指明要创建的信号量包含的信号量个数,如果只是打开信号量,把nsems设置为0即可,第三个参数semflg为操作标志,可

以取如下值:

  • IPC_CREAT:调用semget()时,它会将此值与系统中其它信号量的key值进行比较,如果存在相同的key,说明此信号量

已存在,此时返回该信号量的标识符,否则新建一个信号量并返回其标识符。

  • IPC_EXCL:该宏必须和IPC_CREAT一起使用,否则没有意义。当semflg取IPC_CREAT|IPC_EXCL时,表示如果发现信号

量已经存在,则返回错误,错误码为EEXIST。

信号量的控制:

使用信号量时,往往需要对信号量进行一些控制操作,比如删除信号量、对内核维护的信号量的数据结构semid_ds进行

设置、获取信号量中信号值等。通过semctl控制函数可以完成这些操作,该函数定义在<sys/sem.h>中,如下所示:

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

函数中,参数semid为信号量的标示符(即通过semget函数的到的值);参数semnum标示一个特定的信号;参数cmd指明控制

操作的类型;最后的“...”说明函数的参数是可选的,它依赖于第三个参数cmd,它通过共用体变量semun选择要操作的参数。

union semun
{
int val; //仅用于SETVAL操作类型,设置某个信号量的值等于val
struct semid_ds *buf; //用于IPC_STAT和IPC_SET操作,存取semid_ds结构
unsigned short *array; //用于SETALL和GETALL操作
struct seminfo *__buf; //为控制IPC_INFO提供的缓存
};

参数cmd通过宏来指示操作类型,通常取以下几个宏:

  • GETVAL:把semval的当前值作为函数返回值返回。既然信号量决不会时负数(semval被声明为一个unsigned short整数),

那么成功的返回值总是非负数。

  • SETVAL:把semval值设置为val。如果操作成功,那么相应信号量在所有进程中的信号量调整值将被设置为0。
  • IPC_RMID:把由semid指定的信号量集从系统中删除掉。

信号量的操作:

信号量的值与相应资源的使用情况有关,当它的值大于0时,表示当前可用资源的数量,当它的值小于0时,其绝对值表

示等待使用该资源的进程个数。信号量的值仅能由PV操作来改变。使用semget打开一个信号量集后,对其中一个或多个信号

量的操作就使用semop函数来执行。该函数原型为:

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

函数的参数semid为信号量的标示符,参数sops指向进行操作的结构体数组首地址,参数nsops指出将要进行操作的信号量

的个数。semop函数调用成功返回0,否则返回-1。

semop的第二个参数sops指向的结构体数组中,每个sembuf结构体对应一个特定的信号操作。该结构体为:

struct sembuf
{
unsigned short sem_num; //信号量在信号集中的索引
short sem_op; //操作类型
short sem_flg; //操作标志
};

sem_op的取值和意义:

  • sem_op>0:信号量加上sem_op的值,表示进程释放控制的资源。
  • sem_op=0:如果没有设置IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量值为0;否则进程不会睡眠,直接返回

EAGAIN。

  • sem_op<0:信号量加上sem_op的值。若没有设置IPC_NOWAIT,则调用进程阻塞,直到资源可用;否则进程直接返回

EAGAIN。

下面是对信号量进行操作的一个例子:

// myipc.h
#pragma once #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h> union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
}; key_t Ftok(const char *pathname,int proj_id)
{
key_t key= ftok(pathname,proj_id);
if(key== -)
{
perror("ftok.");
exit();
}
return key;
}
#include "myipc.h"

int main()
{
key_t sem_key= Ftok("mysem",0xff);
int sem_id= semget(sem_key,,IPC_CREAT);
if(sem_id== -)
{
perror("semget.");
exit();
}
else
{
printf("sem key = 0x%x,sem id = %d\n",sem_key,sem_id);
}
int ret;
union semun init;
init.val= ;
semctl(sem_id,,SETVAL,init);
struct sembuf info;
info.sem_num= ;
info.sem_op= ;
info.sem_flg= ;
semop(sem_id,&info,);
ret= semctl(sem_id,,GETVAL);
printf("sem value = %d\n",ret);
ret= semctl(sem_id,,IPC_RMID);
if(ret== -)
{
printf("Remove sem error.\n");
}
else
printf("Remove sem ok.\n");
return ;
}

IPC进程间通信---信号量的更多相关文章

  1. 【转载】Linux的进程间通信-信号量

    原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...

  2. Android开发之IPC进程间通信-AIDL介绍及实例解析

    一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...

  3. System V IPC 之信号量

    本文继<System V IPC 之共享内存>之后接着介绍 System V IPC 的信号量编程.在开始正式的内容前让我们先概要的了解一下 Linux 中信号量的分类. 信号量的分类 在 ...

  4. 【IPC进程间通信之四】数据复制消息WM_COPYDATA

    IPC进程间通信+数据复制消息WM_COPYDATA                IPC(Inter-Process Communication,进程间通信).         数据复制消息WM_C ...

  5. IPC 进程间通信方式——信号量

    信号量 本质上是共享资源的数目,用来控制对共享资源的访问. 用于进程间的互斥和同步 每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对多对信号量一次性操作.对信号量集中所有的操 ...

  6. UNIX:高级环境编程 - 第十五章 IPC:进程间通信

    IPC(InterProcess Communication)进程间通信.为啥没有进程间通信,这是因为进程间都是同步的关系,不需要通信. 1.管道 1.1管道特点: (1)半双工的(即数据只能在一个方 ...

  7. Linux - 进程间通信 - 信号量

    一.概念 简单来讲,信号量是一个用来描述临界资源的资源个数的计数器. 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件.外部设备等)来实现进程间通信, 他本身 ...

  8. Linux进程间通信—信号量

    二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...

  9. IPC 进程间通信

    linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它 ...

随机推荐

  1. 1.zookeeper的安装

    1.解压zk压缩包 tar -zxvf (zk压缩包路径名) -C (解压目标目录路径) 2.在zk解压目录下新建data文件夹 mkdir data 3.在data文件夹下新建myid vi myi ...

  2. C# 读写xml、excel、word、ppt、access

    C# 读写xml.excel.word.access 这里只是起个头,不做深入展开,方便以后用到参考 读写xml,主要使用.net  的xml下的document using System;using ...

  3. WinSock2 API

    title: WinSock2 API tags: [WinSock, 网络编程, WinSock2.0 API, 动态加载, WinSock 异步函数] date: 2018-07-21 10:36 ...

  4. 【转】 ASP.NET使用ICallbackEventHandler无刷新验证用户名是否可用

    功能说明:当用户在用户名输入框输入字符并焦点离开此输入框时,自动到数据库用户表中验证此用户名是否已被注册,如果已被注册,显示[不可用],反之,显示[可用],期间页面不刷新,读者也可以考虑将提示文字换成 ...

  5. user purchase behavior:

    user purchase behavior: 参考网址: online shopping frequent https://www.bigcommerce.com/blog/ecommerce-tr ...

  6. matlab练习程序(旋转、径向模糊)

    还记得过去写过径向模糊,不过当时效果似乎不好. 这次效果还可以,程序中用的算法是: 1.求当前处理点和图像中心点之间的距离r与角度ang; 2.通过对r的修改得到径向模糊. 3.通过对ang的修改得到 ...

  7. raid管理

    raid管理 使用工具命令 storcli64 查看磁盘状态 storcli64 /c0 show 注:现在磁盘状态为UGood状态,表示可以直接制作raid 若磁盘状态为JBOD,则制作raid时会 ...

  8. 使用gulp解决外部编辑器修改Eclipse文件延迟刷新

    本人前端用惯了Hbuilder,修改了eclipse项目中的文件后,由于是外部编辑器修改过的,eclipse不会自动部署更新,一般按F5刷新项目,或者在 preferences > genera ...

  9. SQL Server ->> Move characters in string N position(s) forward/backward based on ASCII table(根据ASCII表的排列顺序将字符串内的数值往前或者后移N个位)

    去年无聊的时候想到想玩一下根据ASCII表的排列顺序将字符串内的数值往前或者后移N个位,顺便看一下是T-SQL性能好还是用C#写CLR函数处理得快.结果是在50万行以下其实两者差距很小,当然这是在我的 ...

  10. oracle_union_operator

    SQL: UNION Operator This SQL tutorial explains how to use the SQL UNION operator with syntax and exa ...