信号量互斥编程

信号量通讯的目的有两个:①实现进程互斥②实现进程同步
两个进程对同一资源同时访问有时会造成数据混乱,如进程A,B都要往同一文件写入数据,当进程A写入一部分时,进程B开始写数据,这会导致文件里的数据混乱。使用信号量互斥通讯可以解决这种问题。信号量的实质是一个数字,它标志着进程能否访问资源。信号量的操作主要有获取信号量和释放信号量。使用资源前需要成功获取信号量,使用后需要释放信号量。
信号量(又名信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。

信号量可分为两类:
1.二值信号灯:信号灯的值只能取0或1
2.计数信号灯:信号灯的值可以取任意非负值。
信号量的编程流程一般为:
①打开信号量,获取一个标示符
②利用标示符对信号量进行操作
对信号量进行编程涉及到键值的概念。进程要打开一个文件,需要知道该文件的文件名从而找到该文件并打开,而键值类似于文件名。系统的每个ipc对象(信号量,消息队列,共享内存等)在系统中都有一个键值与之对应。不管有没有打开ipc对象,这个键值都是存在的。若要打开一个信号量则必须知道键值。有些文件不存在键值,则可指定它的键值,指定方法有两种:
①任意指定一个数。缺点是若这个数已经被别的IPC对象所使用了,则在与新创建的信号量关联时就会失败。
②构造一个尽量不会被别的IPC对象用到的数方法:使用key_t ftok( char * fname, int id )

semget函数

原型:int semget(key_t key,int nsems,int semflg)
头文件:<sys/types.h><sys/ipc.h><sys/sem.h>
功能:打开/创建一个信号量集合,成功返回信号量集合标示符(不是获取信号量),失败返回-1
参数:key:键值
     semflg:可以取值IPC_CREAT,若与key相关联的信号量不存在时会创建一个信号量集合
     nsems:创建的这个信号量集合里包含的信号量数目

semctl函数

原型:int semctl(int semid,int semnum,int cmd,.../*union semun arg*/)
头文件:<sys/sem.h>
功能:根据cmd的值进行相应操作
参数:第四个参数是可选的。semid为要操作的信号量集合标示符,semnum为指定要操作的信号量集合里具体的一个信号量,编号从0开始,cmd的取值有10种,其中一种为SETVAL,设置成员semnum的信号量的值,此时第四个参数arg就是要设置的信号量的值。

semop

原型:int semop(int semid,struct sembuf *sops,unsigned nsops)
头文件:<sys/types.h><sys/ipc.h><sys/sem.h>
功能:操作信号量,成功返回0,失败返回-1
参数:semid:要操作的信号量集合标示符
nsops:要操作多少个信号量
struct sembuf结构为:
struct sembuf
{
    unsigned short sem_num;  /*指定要操作的信号量集合里具体的一个信号量,编号从0开始*/
    short sem_op;  /*对信号量的操作,如为-1表示对信号量进行减1操作。只有使结果为非负的操作才能成功操作, 若操作失败则等待直至能操作成功*/
    short sem_flg;
};

实例

进程A往文件myfile里写数据,写入一部分后停止一段时间,然后接着写:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>
void main()
{
    int fd=open("/home/jx/myfile",O_RDWR|O_APPEND,0777);
    key_t key=ftok("/home/jx/myfile",1); /*创建键值*/
    int semid=semget(key,1,IPC_CREAT); /*创建信号量集合,获取标示符*/
    semctl(semid,0,SETVAL,1);/*设置信号量初始值*/
    /*获取信号量*/
    struct sembuf sop;
    struct sembuf *sops=&sop;
    sops->sem_num=0;
    sops->sem_op=-1;

    sops->sem_flg=SEM_UNDO;
    semop(semid,sops,1);

    write(fd,"hello ",6);
    sleep(10);
    write(fd,"world!",6);
    /*释放信号量*/
    sops->sem_num=0;
    sops->sem_op=1;

    sops->sem_flg=SEM_UNDO;
    semop(semid,sops,1);

    close(fd);
}

进程B先判断能否往文件myfile里写数据,若不能则等待

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>
void main()
{
    int fd=open("/home/jx/myfile",O_RDWR|O_APPEND,0777);
    key_t key=ftok("/home/jx/myfile",1); /*创建键值*/
    int semid=semget(key,1,IPC_CREAT); /*创建信号量集合,获取标示符*/
    /*获取信号量*/
    struct sembuf sop;
    struct sembuf *sops=&sop;
    sops->sem_num=0;
    sops->sem_op=-1;

    sops->sem_flg=SEM_UNDO;
    semop(semid,sops,1);

    write(fd,"this is a program",17);

    /*释放信号量*/
    sops->sem_num=0;
    sops->sem_op=1;

    sops->sem_flg=SEM_UNDO;
    semop(semid,sops,1);

    close(fd);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值