Linux进程间通信:信号量(sem)

目录

一 信号量概念:

二 相关函数

semget函数

semctl函数

semop函数


一 信号量概念:

① 信号量又称为信号灯,不以传输数据为主要目的;

② 用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。

核心操作(semop): 

• P(-1):如果有一个任务想要获得已经被占用的信号量时,信号量会将其放入一个等待队列然后让其睡眠。

• V(+1):当持有信号量的进程将信号释放后,处于等待队列中的一个任务讲被唤醒(因为队列中可能不止一个任务),并让其获得信号量。

举例:如果一个公共厕所有3个坑位,p1进来后就剩下2个坑位,当p2和p3进来后,此时剩下0个坑位。当p4在进来,坑位就为-1个,p5在进来,坑位就为-2个。那么坑位(信号量)就会执行P操作,把p4和p5放在等待队列中。当p1完事离开后,坑位(信号量)就执行V操作,将p4放入原p1的坑位,此时的坑位数就位-1,只有p5还在等待队列。以次内推,当p1p2p3p4p5全部完事后,坑位数量又重新为3。(新增一个进程,信号量+1;释放一个进程,信号量-1),这样就可以通过信号量有效的管理和分配资源

二 相关函数

semget函数

功能:获得信号量的ID,由semid来接收

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

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

int key:信号量的键值;

int nsems:信号量的数量;

int semflg:标识/权限 

返回值:成功返回信号量的ID;失败返回-1;

代码示例:

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

int main()
{
        key_t key = ftok("./semget.c",2);//获取key值
        int semid = semget(key,1,0666|IPC_CREAT);//获取信号量ID
        if(semid == -1){
                printf("semget error!\n");
        }
        printf("semget success! semid=%d\n",semid);
        return 0;
}

编译结果:
dhw@dhw-virtual-machine:~/sem$ ./a.out
semget success! semid=0

semctl函数

作用:信号量控制,由该函数中cmd参数所决定

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

int semctl(int semid, int semnum, int cmd, union semun arg);

int semid:信号量ID

int semnum:信号量编号(要操作的那个信号)

int cmd: IPC_STAT(获取信号量的属性);②IPC_SET(设置信号量的属性);③IPC_RMID(删除信号量);④SETVAL(设置信号量的值)

arg: union semun {
               int              val;                 /* SETVAL的值 */④
               struct semid_ds *buf;       /* IPC_STAT, IPC_SET的缓冲区 */①②
               unsigned short  *array;    /* 数组为GETALL, SETALL */
               struct seminfo  *__buf;     /* IPC_INFO缓冲区(linux专用) */
           };

特别说明:要使用cmd中那个编号,就使用arg中对应编号的参数,不一定要全部使用。

返回值:成功返回0;失败返回-1;

semop函数

作用:对信号量进行P&V操作

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

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

int semid:信号量ID

struct sembuf *sops:信号量结构体数组

size_t nsops:要操作信号量的数量

struct sembuf{
       unsigned short sem_num;  /* 要操作信号量的编号*/
       short          sem_op;   /* P/V操作,+1为V操作,释放资源;-1为P操作,分配资源;0为等 
                                                                待,直到信号量的值变为0*/
       short          sem_flg;  /* 0表示阻塞;IPC_NOWAIT表示非阻塞 */
};

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

代码流程:semget() semctl() semop(); 

代码示例:父进程执行的是p操作-1,等待有空缺的资源;子进程执行的是v操作+1,执行子进程。所以下图代码执行结果是:先执行子进程,在执行父进程

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
union semun{
        int val;
};
int main()
{
        key_t key = ftok("./semget.c",2);//获取key值
        int semid = semget(key,1,0666|IPC_CREAT);//获取信号量ID

        union semun semun_union;
        semun_union.val = 0;
        semctl(semid,0,SETVAL,semun_union);

        struct sembuf sem;
        int pid = fork();
        if(pid > 0){
                sem.sem_num = 0;
                sem.sem_op = -1; //p操作-1,等待资源,
                sem.sem_flg = 0;
                semop(semid,&sem,1);
                printf("this is father!\n");
                sem.sem_num = 0;
                sem.sem_op = 1;//还原操作
                sem.sem_flg = 0;
                semop(semid,&sem,1);
        }
        if(pid == 0){
                sem.sem_num = 0;
                sem.sem_op = 1;//v操作+1,进程被唤醒
                sem.sem_flg = 0;
                semop(semid,&sem,1);
                printf("this is child!\n");
        }
        return 0;
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Linux 中,可以使用 `semctl` 系统调用中的 `GETVAL` 命令来获取指定信号量的值。如果该值为0,则表示信号量已经被占用,没有可用的资源。 具体的代码实现可以参考如下示例: ```c #include <stdio.h> #include <stdlib.h> #include <sys/sem.h> int main() { int semid; struct sembuf sb; // 创建信号量semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量 if (semctl(semid, 0, SETVAL, 1) == -1) { perror("semctl"); exit(EXIT_FAILURE); } // 获取信号量的值 printf("Sem value: %d\n", semctl(semid, 0, GETVAL)); // 尝试获取信号量 sb.sem_num = 0; sb.sem_op = -1; // P 操作 sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(EXIT_FAILURE); } printf("Semaphore acquired\n"); // 释放信号量 sb.sem_op = 1; // V 操作 if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(EXIT_FAILURE); } printf("Semaphore released\n"); // 删除信号量集 if (semctl(semid, 0, IPC_RMID, 0) == -1) { perror("semctl"); exit(EXIT_FAILURE); } return 0; } ``` 在这个示例中,我们首先使用 `semget` 系统调用创建了一个信号量集,并使用 `semctl` 系统调用对该信号量进行了初始化。然后使用 `semctl` 系统调用获取了该信号量的值,并输出到控制台。 接下来,我们使用 `semop` 系统调用进行了一次 P 操作,即尝试获取该信号量。如果该信号量的值为0,则该操作将会被阻塞,直到信号量的值变为非0。在本例中,由于我们已经将信号量初始化为1,因此该 P 操作可以顺利完成。 最后,我们使用 `semop` 系统调用进行了一次 V 操作,即释放该信号量。然后使用 `semctl` 系统调用删除了该信号量集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

D.•

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

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

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

打赏作者

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

抵扣说明:

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

余额充值