Linux system V 信号量

在Linux中,信号量是一种用于进程间同步和互斥的机制。它可以用于控制对共享资源的访问,以避免多个进程同时访问造成的竞争条件。

Linux提供了两种类型的信号量:System V信号量和POSIX信号量。

System V信号量是通过系统调用(如semget、semop和semctl)来操作的。它们是用于进程间同步和互斥的基本机制,并且可以在不同进程之间共享。

POSIX信号量是通过库函数(如sem_init、sem_wait和sem_post)来操作的。它们是Linux提供的一种更现代、更灵活的信号量机制,也可以在不同进程之间共享。

无论是System V信号量还是POSIX信号量,它们都可以用于实现各种同步和互斥机制,如互斥锁、条件变量和读写锁等。

System V信号量

  1. semget:创建或获取信号量集。每个信号量集包含多个信号量,每个信号量都有一个唯一的标识符。
  2. semop:用于进行信号量操作,包括P操作(等待信号量)和V操作(释放信号量)。P操作将信号量的值减一,如果它的值小于零,进程将被阻塞。V操作将信号量的值加一,唤醒等待的进程。
  3. semctl:用于进行信号量的控制操作,如获取、设置信号量的值,删除信号量集等。

semget

int senget(key_t key,  int nsems, int semfalg);
  • key:是一个键值,用来标识信号量集。多个进程可以使用相同的key来获取同一个信号量集。
  • nsems:表示信号量集中包含的信号量数量。
  • semflag:指定创建或获取信号量集的标志。可以使用IPC_CREAT来创建新的信号量集,与IPC_EXCL 一起使用来确保创建唯一的信号量集,也可以与其他标志用于权限设置(0666)。*

返回值

  • 成功返回一个信号量集的标识符。
  • 失败返回-1,并设置errno。

示例:

################### 创建一个唯一的信号量 #######################    
	key_t key = ftok("/usr/bin", 255);
    //创建一个信号量集,如果信号量已经存在 返回错误。
    m_semId = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);

################### 打开一个已经存在的信号量 #######################
	
	m_semId = semget(key, 0, 0);

	参数 nsems, semfalg 都将被忽略。

semctl

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

	union semnu
	{
    	int val;
    	struct semid_ds *buf;
    	unsigned short *array;
    	struct seminfo *__buf;
	};

参数:

  • semid:信号量集的标识符,由 semget 函数创建或获取。

  • semnum:表示要操作的具体信号量集中的索引,通常为0表示第一个信号量。

  • cmd:表示要执行的操作,可以是以下之一:

    • GETVAL:获取信号量的当前值。
    • SETVAL:设置信号量的值。
    • GETPID:获取上一次执行semop操作的进程ID
    • GETNCNT:获取等地啊操作的进程数量。
    • GETZCNT:获取等待清零操作的进程数量。
    • SETALL:用于设置一组信号量的值,通常与arg参数中提供的数组一起使用。
    • IPC_STAT:用于获取信号量的信息结果。
    • IPC_SET:用于修改信号量的信息结构,通常与arg参数中提供的sembuf结构一起使用
    • IPC_RMID:从系统中删除信号量集。
    • 等等。
  • arg:一个联合体(union semun),用于传递操作所需的参数,具体内容取决于cmd的值。

返回值:

  • 失败时返回-1,并设置errno。成功时 cmd标黄的 返回对应的值(非负值),其余返回0。

semop

它允许进程对信号量就行P(等待)、V(释放)操作,以实现进程之间的同步和互斥。

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

// sembug 的定义
struct sembuf {
    short sem_num;  // 信号量在信号量集中的索引,从0开始
    short sem_op;   // 操作,通常为正数表示V操作,负数表示P操作
    short sem_flg;  // 操作标志,通常为0,取值有 SEM_UNDO | IPC_NOWAIT
};

如果sem_op > 0,信号量的值会加上sem_op的值,表示进程释放控制的资源。
如果sem_op = 0,如果没有设置IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量的值为0;否则进程不会睡眠,直接返回EAGAIN。
如果sem_op < 0,信号量的值会加上sem_op的值。如果没有设置IPC_NOWAIT,则调用进程会阻塞,直到资源可用;否则进程直接返回EAGAIN。

参数:

  • semid:信号量集的标识符,由semget函数创建或获取。
  • sops:指向sembuf结构数组的指针,该结构包含要执行的操作和信号量索引。
    • SEM_UNDO:用于启用进程终止时的自动撤销操作。如果设置了此标志,并且进程在执行 semop 操作之后非正常退出,内核将自动执行撤销操作,将信号量的值还原为操作之前的状态,以避免资源泄漏。这通常用于防止由于进程异常退出而导致的资源泄漏。
    • IPC_NOWAIT:用于非阻塞操作。如果设置了此标志,并且 semop 操作不能立即执行(例如,由于信号量值不允许),则该操作不会等待,而是立即返回错误。
  • nsops:表示sops数组中操作的数量。

示例:

################### 执行P操作(等待信号量) ######################
struct sembuf operation;
operation.sem_num = 0;   // 操作的信号量索引
operation.sem_op = -1;   // 执行P操作
operation.sem_flg = SEM_UNDO;

semop(semid, &operation, 1);


################### 执行V操作(释放信号量) ######################
struct sembuf operation;
operation.sem_num = 0;   // 操作的信号量索引
operation.sem_op = 1;    // 执行V操作
operation.sem_flg = SEM_UNDO; //程序异常退出时会对该操作进行撤销,该程序中所有设置了该标志的操作都将撤销。
semop(semid, &operation, 1);

sops参数中包含的操作集 按数组顺序自动执行,也就是说,这些操作要么作为一个完整的单元执行,要么根本不执行。如果不能立即执行所有操作,则系统调用的行为取决于各个sem_flg字段中是否存在IPC IPC_NOWAIT标志。

    # 两个信号量的初始化均设置为1

	struct sembuf sops[2] = {0};
    sops[0].sem_flg = SEM_UNDO | IPC_NOWAIT;
    sops[0].sem_num = 0;
    sops[0].sem_op = 0;

    sops[1].sem_flg = SEM_UNDO;
    sops[1].sem_num = 1;
    sops[1].sem_op = -1;

    int rv = semop(m_semId, &sops[0], 2);
    if (0 != rv)
    {
        printf("Lock error, errno = %d, errmsg = %s\n", errno, strerror(errno));
        return rv;
    }

上面这个示例中同时操作信号量集中的两个信号量, 但是第一个信号量不能立即执行但是因为又设置了 IPC_NOWAIT属性, 所以此时semop失败,errno设置为EAGAIN(并且没有执行sops中的任何操作)。

注意事项

  • 创建好的信号量集在程序结束时需要手动进行释放,如果没有释放即使程序在退出时也不会被系统回收。(可以使用ipcrm 命令删除信号量)。
  • 多个进程使用同一个信号量集时,如果有一个进程对该信号量集进行了释放,那么其他的进程在对该信号量集操作时将会失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值