Linux操作系统——简单进程同步

2023年 12月 6日 20.5k 0

一、信号量相关函数

1. 创建信号量集

本次实验使用信号量机制来实现进程的同步与互斥,因此首先需要创建信号量集。

使用函数semget可以创建信号量集,它的原型如下:

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

其中,key是创建信号量集的键,nsems是信号量集中信号量量的数量;

semflg是指定的选项及其权限位,包含IPC_CREAT(创建新的信号量集)、IPC_EXCEL(如果信号量集已经存在,则返回错误)等。

这个函数创建的是一个信号量集,其中包含多个信号量,可以通过函数semop来访问信号量集中的某个信号量,或者使用semctl函数来对信号量进行操作,一般创建数据集后都要首先使用semctl对每个信号量设置初始值。semop和semctl函数的介绍在下面。

2. 获取信号量集

一个进程创建号信号量集后,另一个进程想要访问这个信号量集,可以使用semget函数传入KEY值来获取该信号量集的id,该函数原型如下:

int semid = semget(KEY, 0, 0);

上述代码只为获取一个已经存在的信号量集,不需要nsems和semflg,全部为0即可。获取成功会返回信号量集id,如果获取失败的话会返回-1 。

3. 等待、通知信号量集

使用semop函数可以访问一个信号量集,进行获取(P操作)和释放(V操作),其原型如下:

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

semid是使用semget函数获取到的信号量集的id;

sops是一个sembuf类型的结构,用于描述信号量的操作:等待、通知等,其定义如下:

struct  sembuf{

       short sem_num;    // 要访问的信号量在信号量集中的索引

       short sem_op;    // 对信号量的操作,为负数是P操作,正数是V操作

       short sem_flg;   // 操作标志,可以是0或IPC_NOWAIT(非阻塞方式)

}

nsops是指定信号量集中操作的信号量个数。

4. 控制信号量集

要对整个信号量集进行操作可以使用semctl函数,其原型如下:

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

semid是由semget函数返回的信号量集id

semnum是信号量在信号量集中的索引

cmd是控制命令,用于对信号量执行指定的操作,命令包括:

IPC_STAT:获取信号量集合的属性信息,将结果写入指定的结构体中。

IPC_SET:设置信号量集合的属性信息,使用指定的结构体中的值进行设置。

GETVAL:获取指定信号量的值。

SETVAL:设置指定信号量的值。

GETALL: 获取信号量集合中所有信号量的值

SETALL: 设置所有信号量的值

GETPID:获取最后一个执行 semop() 操作的进程 ID。

GETNCNT:获取等待该信号量值增加的进程数。

GETZCNT:获取等待该信号量值变为 0 的进程数。

IPC_RMID:删除信号量集合。

二、简单进程同步

现在使用上面给出的函数编写几个程序实现进程同步。

信号量机制实现进程同步需要使用一些简单的信号量集操作,包括创建信号量集,P操作,V操作,删除信号量集。

1. 创建信号量集

createSem.cpp

#include

#include

#include

#include

using namespace std;

#define KEY 2002

int main(){

int semid = semget(KEY, 1, IPC_CREAT);

semctl(semid, 0, SETVAL, 0);

 

}

上面代码使用semid函数创建一个只包含一个信号量的信号量集,随后使用semctl将该信号量的值初始化为0 。

2. P操作

p1.cpp

#include

#include

#include

#include

#define KEY 2002

using namespace std;

int main(){

int semid = semget(KEY, 0, 0);

struct sembuf *sops = new sembuf;

sops->sem_num = 0;

sops->sem_op = -1;

sops->sem_flg = 0;

if(semop(semid, sops, 1) == -1){

char err[] = "semop";

perror(err);

exit(1);

}

cout sem_op = 1;

sops->sem_flg = 0;

if(semop(semid, sops, 1) == -1){

char err[] = "semop";

perror(err);

exit(1);

}

return 0;

}

上面代码与p1基本时一样的,只是修改了sem_op,改为1(V操作,信号量加1),执行该程序后,对应信号量会加一,原本阻塞的程序就能结束等待,继续执行下去。

4. 删除信号量集

deletSem.cpp

信号量集使用完毕后需要删除信号量集,使用semctl函数实现,控制命令选择IPC_RMID。

#include

#include

#include

#include

using namespace std;

#define KEY 2002

int main(){

int semid = semget(KEY, 0, 0);

semctl(semid, 0, IPC_RMID, 0);

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论