linux下的信号量(semaphore)

1.信号量:( Semaphore)
    当有多个进程试图访问同一个文件并要更新这个文件,文件中的数据就会面临被破坏的危险。
    不同的进程要求向文件中写入数据,问题在于对文件进行更新的那部分代码,这部分真正执行文件更新的代码需要排他式的执行,他们被称为临界区域,这段代码被称为临界代码。
    信号量的出现就是你为了解决访问一个共享资源所引起的的问题。
    信号量是一个特殊的变量,它只取0和整数值,程序对信号量的操作都是原子操作。
    信号量只允许对它的值有两个操作 ,使其值增加:等待(wait)与信号(signal)发送信号。
    (1)P(信号量变量):用于等待
    (2)V(信号量变量):用于发送信号
    PV操作的具体定义:
    P(SV):如果SV的值大于0,就减1;如果等于0.就挂起该进程。
    V(SV):如果有其他进程等待SV被挂起,就让他恢复运行;如果没有进程因等待SV而被挂起,就给他+1.
2.信号量的工作机制:
    假设两个进程p1和p2,某一个时刻对一个文件进行独占式的访问。
    可以定义一个二进制信号量SV,该变量初始值为1,这两个进程都可以访问。要想对代码中的临界区域进程访问,这两个进程需要执行相同的处理步骤:
    P(SV);如果zsv大于0,减小sv.如果sv为0,则挂起这个进程的执行
    V(SV);如果有进程被挂起等待sv,使其恢复执行。若果没有进程被挂起等待,则增加sv
 
    一旦一个进程进行了P操作,进程将获得信号量,并可以进入临界区域,执行对文件的更新操作。而这个时候第二个进程将会被组停止进入这个临界区域,因为当这个进程试图执行P操作时,发现sv为0,这个时候他就会被挂起来等待第一个进程离开这个临界区域,并执行V操作,来释放这个信号量。然后这个进程得到信号量,才可以进行操作。
3.linux下的信号量:
    信号量的定义:
    #include <sys/types.h>
    #inlcude <sys/ipc.h>
    #inlcude <sys/sem.h>
    int semctl(int semid,int semnum,int cmd,...);
    int semget(key_t key,int nsems,int semflg);
    int semop(int semid,struct sembuf *sops,unsigned nsops);
    (1)semget函数
        创建一个新信号量或取得一个已经存在的信号量的键值。参数key是一个整数值,不相关的进程可以通过它来间接访问同一个信号量。程序对所有的信号量的访问都是间接的,它先提供一个键,再由系统生成一个相应的信号量标示符。只有semget函数才能直接使用信号量键,所有其他的信号量函数都是使用semget函数返回的信号量标示符。
        关于键值key,有一个特殊的信号量key值,IPC_PRIVATE(通常为0),作用是创建一个只有当前的进程可以访问的信号量。
        nsems是指定的信号的数目,一般取值都是1.
        semflg是一组标志,与open函数的标志相似。
        semget函数成功返回一个整数值,即信号量标示符,失败返回-1.
    (2)semop函数:
        用于改变信号量的值。
semid是由semget返回的信号量的标示符。
        struct sembuf的成员如下:
        struct sembuf
{
        unsigned short sem_num;
        short sem_op;
        short sem_flg;
}
        第一个成员sem_num是信号量编号,除非用了一组信号量,一般取值为0,表示使用单个信号量
        第二个成员sem_op是信号量在一次操作中需要改变的数值,通常只有两个值,一个是-1,即P操作,它等待信号量变为可用;一个是+1,即V操作。
        第三个成员sem_flg通常被设为SEM_UNDO.它将使得操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下退出,操作系统将自动释放该进程的信号量。
nsops:通常取值为1,表示操作数组中元素的个数。    

    (3)semctl函数
        该函数用来控制信号量信息。
semid是semget函数返回的标识符。
semnum:信号量的编号,通常设为0,表示使用单个信号量。
cmd参数是将要采取的动作:
(1)IPC_STAT:获得该信号量的semid_ds结构,并存放在第四个参数指向的结构中。
(2)IPC_SETVAL:将信号量值设置为第四个参数值
(3)IPC_GETVAL:返回当前信号量的值
(4)IPC_RMID:从当期的系统中,删除信号量。

如果还有第四个参数,它将会是一个union semun结构;
    union semun
    {
        int val;//SETVAL的值
        struct semid_ds *buf;    //IPC_STAT,IPC_SET的buf
        unisgned short *array;    //GETALL,SETALL的数组
    }
    两个通常的cmd参数值为:
    SETVAL:把信号量初始化为一个已知的值。使这个值通过union semun中的val成员设置。作用是在信号量第一次使用之前对它进行设置。
    IPC_RMID:删除一个已经不需要继续使用的信号量标示符。使用这两个参数时,成功返回0,失败返回-1.



4.linux下使用信号量的通常步骤:

(1)创建信号量或获得已经存在的信号量,先调用semget()函数。不同的进程通过使用同一个信号量键值来获得同一个信号量。

(2)初始化信号量,此时使用semctl()函数的SETVAL操作。当使用二维信号量时初始化为1.

(3)进行信号量的PV操作,此时调用semop函数,用来改变信号量的值,在这一步实现进程之间的同步和互斥的核心操作。

(4)当不再需要使用信号量时,则使用semclt函数的IPC_RMID.



实例参见代码类.

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShaYQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值