ITPub博客

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

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

原创 Linux操作系统 作者:晨晨mak 时间:2023-12-05 09:30:24 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<iostream>

#include<sys/sem.h>

#include<sys/types.h>

#include<sys/ipc.h>

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<iostream>

#include<sys/sem.h>

#include<sys/types.h>

#include<sys/ipc.h>

#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 << "获取成功" << endl;

return 0;

}


上一个程序createSem创建完信号量集后,信号量集就保存在缓冲区中,此时另一个程序可以使用semget函数访问该信号量集,使用同样的键值KEY就能访问到上一个进程创建的信号量集。


上述代码首先获取已经创建好的信号量集,随后定义sembuf类型结构指针sops,设置访问信号量索引sem_num为0,信号量操作sem_op为-1(p操作,信号量减一),操作标志为0 。接着就使用semop函数传入sops对信号量进行操作,如果操作失败(如信号量集不存在或信号量索引非法等)就输出错误信息,结束程序。如果获取成功则会执行下面的语句打印“获取成功”,如果进行P操作时该信号量为0,此时进行会阻塞,等待其他进程释放信号,为了简化问题,一开始设置信号量为0,此时执行p1程序一定会阻塞。


3. V操作

p2.cpp


#include<iostream>

#include<sys/sem.h>

#include<sys/types.h>

#include<sys/ipc.h>

#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);

}

return 0;

}


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


4. 删除信号量集

deletSem.cpp


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


#include<iostream>

#include<sys/sem.h>

#include<sys/types.h>

#include<sys/ipc.h>

using namespace std;

#define KEY 2002

int main(){

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

semctl(semid, 0, IPC_RMID, 0);



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70001647/viewspace-2998725/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-06-05

  • 博文量
    11
  • 访问量
    12193