信号量编程

来源:互联网 发布:淘宝怎么装修店铺 编辑:程序博客网 时间:2024/06/10 14:01

信号量 定义:

信号量(Semaphore)是Linux进程间通信的一种方式。但是,与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步

信号量的实质是一个数字

在程序开始时,设置信号量为1,先获取到信号量的进程将信号量 -1 使信号量为0。信号量为0时,需要获取它的进程会自动等待,直到正在使用信号量的进程释放信号量即将信号量 +1,信号量由0变为1后,其他进程才能重新去获取信号量。

也就是说,对信号量-1是获取信号量,对信号量+1是释放信号量。

键值:

IPC(进程间通信)对象是活动在内核级别的一种进程间通信的工具。存在的IPC对象通过它的标识符来引用和访问,这个标识符是一个非负整数,它唯一的标识了一个IPC对象,这个标识符就叫做“键值”。键值对于IPC对象就相当于文件名对于文件一样。

IPC对象可以是消息队列信号量共享内存中的任意一种类型。在Linux系统中键值被声明成整数,所以可能存在的最大键值为65535。这里键值与文件描述符有所不同。

使用open函数打开一个文件时,返回的文件描述符的值为当前进程最小可用的文件描述符数组的下标。

IPC对象删除或创建时相应的键值的值会不断增加到最大的值,归零循环分配使用。

指定键值:
1.任意指定一个数
缺点:这个数可能已经被别的IPC对象(消息队列,共享内存)所使用了,在与新创建的信号量关联时就会失败。
2. 构造一个尽量不会被别的IPC对象用到的数
方法:使用key_t ftok( char * fname, int id )

键值的数据类型为key_t ,也就是int类型。参数fname是信号量等IPC对象的文件名,可以自拟。参数id是项目id,可以设为1。若文件名和ID不同,则键值不同。

创建/打开信号量集合

函数原形:
int semget(key_t key, int nsems, int semflg);

函数功能:
获取信号量集合的标识符,也可以创建一个信号量集合,并获取标识符。

所属头文件:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

返回值:
若成功,返回信号量集合的标识符;若失败,返回-1.

参数说明:
key:键值,标志信号量集合。使用ftok函数创建键值 key_t ftok(char *fname, int id);
nsems:若本函数创建了新的信号量集合,创建的信号量集合中信号量的数目为nsems。
semflg:标志,可以取IPC_CREAT,若key指定的信号量集合不存在还可以创建一个信号量集合。

操作信号量

函数原形:
int semop(int semid, struct sembuf *sops, unsigned nsops);

函数功能:
操作信号量集合中的信号量。

所属头文件:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

返回值:
成功返回0,失败返回-1.

参数说明:
semid:要操作的信号量集合的标识符。
nsops:要操作的信号量的个数
sops:对信号量进行的操作,1个sembuf只能对应一个信号量的操作,因此是sembuf指针,成员如下:
这里写图片描述
sem_num:表示信号量在集合中的编号。
sem_op:表示操作,小于0获取信号量如+1,大于0释放信号量如-1。当信号量值为0,进程自动等待。
sem_flg 标志位,可以为 SEM_UNDO,表明系统自动释放信号量

信号量控制操作函数

函数原形:
int semctl(int semid, int semnum, int cmd);

函数功能:
信号量控制操作函数,当信号量的值为0时,需要获取它的进程自动等待,直到信号量释放变为1。

所属头文件:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

返回值:
若成功,返回值根据cmd参数来定,若失败,返回-1

参数说明:
semid:信号量ID
semnum:信号量在集合中的编号
cmd: 10种操作之一,如SETVAL设置信号量值、GETVL获取信号量的值 等。

信号量互斥编程 举例:

1、进程A

/* 公告栏问题,同学A,在黑板上写下“数学课取消” */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h>//公告栏问题,同学A在黑板上写下“数学课取消”,同学B在黑板上写下“英语课考试”//打开文件,写上“数学课”,休息10s,再写上“取消”,关闭文件void main(){    int fd;    key_t key;//键值    int semid;//信号量集合标识符    struct sembuf sops;//对信号量集合进行操作的结构体    int set;    //创建键值    key = ftok("./key", 1);//路径 项目ID    //创建和打开信号量集合    semid = semget(key, 1, IPC_CREAT);    //看一下信号量的值为多少    set = semctl(semid, 0, GETVAL);//获取信号量的值    printf("the set value is %d.\n", set);    //设置信号量的初始值    semctl(semid, 0, SETVAL, 1);//最后一个参数是设置的信号量的值    //获取信号量    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = -1;//对信号量的操作,获取信号量,-1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);    fd = open("./board.txt", O_RDWR | O_APPEND);    write(fd, "Math class", 11);    sleep(10);    write(fd, "is cancel", 10);    close(fd);    //释放信号量    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = +1;//对信号量的操作, 释放信号量,+1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);}

2、进程B

/* 公告栏问题,同学B,在黑板上写下“英语课考试” */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h>//打开文件,写上英语课考试,关闭文件void main(){    int fd;    key_t key;//键值    int semid;//信号量集合标识符    struct sembuf sops;//对信号量集合进行操作的结构体    int set;    //创建键值    key = ftok("./key", 1);//路径 项目ID,与A同学使用相同的键值    //打开信号量集合    semid = semget(key, 1, IPC_CREAT);//A同学已经创建好了信号量集合    //看一下信号量的值为多少    set = semctl(semid, 0, GETVAL);//获取信号量的值    printf("the set value is %d.\n", set);    //获取信号量     //获取不成功就等待    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = -1;//对信号量的操作,获取信号量,-1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);//自动等待    fd = open("./board.txt", O_RDWR | O_APPEND);    write(fd, "English exam", 13);    close(fd);    //释放信号量    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = +1;//对信号量的操作, 释放信号量,+1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);}

进程同步

一组并发进程进行互相合作、互相等待,使得各进程按一定的顺序执行的过程称为进程间的同步

信号量同步编程 举例:

1、进程A

/* 生产者和消费者问题,生产者文件,产生产品文件production.txt */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h>//创建产品文件,休息,写入数据,关闭文件void main(){    int fd;    key_t key;//键值    int semid;//信号量集合标识符    struct sembuf sops;//对信号量集合进行操作的结构体    int set;    //创建键值    key = ftok("./key", 1);//路径 项目ID    //创建和打开信号量集合    semid = semget(key, 1, IPC_CREAT);    //看一下信号量的值为多少    set = semctl(semid, 0, GETVAL);//获取信号量的值    printf("the set value is %d.(producor)\n", set);    //设置信号量的初始值    semctl(semid, 0, SETVAL, 0);//最后一个参数是设置的信号量的值    //生产产品文件    fd = open("./product.txt", O_RDWR | O_CREAT);    sleep(5);    write(fd, "This product is finished", 25);    close(fd);    //释放信号量    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = +1;//对信号量的操作, 释放信号量,+1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);}

2、进程B

/* 生产者和消费者问题,消费者文件,将product.txt剪切到指定文件夹 */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h>//取走产品文件void main(){    int fd;    key_t key;//键值    int semid;//信号量集合标识符    struct sembuf sops;//对信号量集合进行操作的结构体    int set;    //创建键值    key = ftok("./key", 1);//路径 项目ID    //创建和打开信号量集合    semid = semget(key, 1, IPC_CREAT);    //看一下信号量的值为多少    set = semctl(semid, 0, GETVAL);//获取信号量的值    printf("the set value is %d.(customer)\n", set);    //获取信号量    sops.sem_num = 0;//信号量在集合中的编号    sops.sem_op = -1;//对信号量的操作,获取信号量,-1    sops.sem_flg = SEM_UNDO;//系统自动释放信号量     semop(semid, &sops,1);    //取走产品文件    system("mv ./product.txt ./ship/"); //移动文件}
0 0
原创粉丝点击