ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux中的System V信号量

2020-12-28 08:34:43  阅读:177  来源: 互联网

标签:stdout int System 信号量 sleep Linux sem include


在进程同步,并发运行时,保证按序地访问共享资源是十分重要的。因此引入了临界区的概念,一次只能有一个线程进入临界区完成他的指令。而信号量(semaphore)的作用,类似于一个交通信号灯,它负责进程协作,因此信号量又称为信号灯。

在Linux系统中,它提供两种信号量:

  • 内核信号量,由内核控制路径使用

  • 用户态进程使用的信号量,这种信号量有两种接口,POSIX信号量和SYSTEM V信号量。

    信号量的本质是一个计数器。一个较为常见的用法,是为每个资源都会分配一个信号量。记信号量为S,除了初始化之外,有两个标准原子操作:wait()signal()

System V信号量接口

  • semget

    创建一个新信号量或取得一个已有信号量

    int semget(key_t key, int num_sems, int sem_flags);
    

    key是一个整数值(唯一非零),可以理解成是信号量的标识符。

    num_sems指定了需要的信号量数目,通常为1。

    sem_flags是一组标志,当创建一个新的信号量时,设定权限与值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

    函数成功返回一个相应信号标识符(非零),失败返回-1

  • semctl

    直接控制信号量信息

    int semctl(int sem_id, int sem_num, int command, ...);
    

    第二个参数是操作信号在信号集中的编号,第一个信号的编号是0

    第三个参数command通常是下面两个值中的其中一个:

    SETVAL:用来把信号量初始化为一个已知的值。

    IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。

    如果有第四个参数,它通常是一个union semum结构,定义如下:

    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *arry;
    };
    
  • semop

    改变信号量的值

    int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
    

    sem_id是由semget返回的信号量标识符,sembuf结构的定义如下:

    struct sembuf{
        short sem_num;//除非使用一组信号量,否则为0
        short sem_op;//信号量在一次操作中需要改变的数据,-1即P(等待)操作,+1即V(发送信号)操作。
        short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量
    };
    

进程同步实例

无信号量实例
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
	pid_t pid;
	pid = fork();
	srand(pid); 
	if(pid > 0) // parent process
	{
		char a = 'A'; // char to print
		for(int i = 0; i < 10; ++i)
		{
			printf("%c", a);
			fflush(stdout); // flush stdout buffer
			sleep(1);

			printf("%c", a);
			fflush(stdout); 
			sleep(1);
		}
	}
	else // child process
	{
		char b = 'B'; 
		for(int i = 0; i < 10; ++i)
		{
			printf("%c", b);
			fflush(stdout); 
			sleep(1);

			printf("%c", b);
			fflush(stdout); 
			sleep(1);
		}
	}
	printf("\n%d - finished\n", getpid());
	sleep(3);
	return 0;
}

运行结果

有信号量实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define SEMKEY 0x00002222 // set a key for semaphore

union semun // union for semaphore
{
	int val;
	struct semid_ds *buf;
	unsigned short  *array;
};

struct sembuf p = { 0, -1, SEM_UNDO};
struct sembuf v = { 0, +1, SEM_UNDO};

int main()
{
	int sem_id = semget(SEMKEY, 1, 0666 | IPC_CREAT); // get semaphore  
	
	union semun sem_union;
	sem_union.val = 1;
	if(semctl(sem_id, 0, SETVAL, sem_union) < 0)
	{
		perror("semctl error");
		return -1;
	}
	int pid;
	pid = fork();
	srand(pid); 
	if(pid > 0) // parent process
	{
		char a = 'A'; // char to print
		for(int i = 0; i < 10; ++i)
		{
			if(semop(sem_id, &p, 1) < 0) // P operation
			{
				perror("semop p error");
				return -1;
			}
			printf("%c", a);
			fflush(stdout); // flush stdout buffer
			sleep(1);

			printf("%c", a);
			fflush(stdout); 
			if(semop(sem_id, &v, 1) < 0) // V operation
			{
				perror("semop v error");
				return -1;
			}
			sleep(1);
		}
	}
	else // child process
	{
		char b = 'B'; // char to print
		for(int i = 0; i < 10; ++i)
		{
			if(semop(sem_id, &p, 1) < 0) // P operation
			{
				perror("semop p error");
				return -1;
			}
			printf("%c", b);
			fflush(stdout); // flush stdout buffer
			sleep(1);

			printf("%c", b);
			fflush(stdout); 
			if(semop(sem_id, &v, 1) < 0) // V operation
			{
				perror("semop v error");
				return -1;
			}
			sleep(1);
		}
	}
	printf("\n%d - finished\n", getpid());
	sleep(3);
	if (pid > 0)
	{
		system("ipcrm -S 0x00002222");
	}
	return 0;
}

运行结果

因为设定信号量的关系,一个线程在临界区内一定会执行两次print()操作,所以A或B一定成对出现。

标签:stdout,int,System,信号量,sleep,Linux,sem,include
来源: https://www.cnblogs.com/ephemerally/p/14199863.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有