10.Linux网络编程-system v信号量

一:信号量简介
信号量本质就是一个计数器,用于统计临界资源数目的计数器,信号量是用来调协进程对共享资源的互斥访问,采用PV原语的原理。它的P(sv)和V(sv)行为是这样的:
P(sv):要访问受保护的资源的进程或者线程试图对信号量的值减1,如果信号量的值现在不可用,即信号量为0,减1操作将被阻塞(休眠),直到信号量大于0时,才会得以继续执行;
V(sv):要释放受保护的资源时,信号量的值将会加1,此时信号量的值大于0,其他请求该资源被信号量阻塞的线程或者进程将被唤醒;
总之,信号量为0(信号量不能小于0),无可用资源,信号量大于0,有可用资源。

二:函数简介

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);

@semget:新建信号量
@int :成功返回相应的信号量标识符,失败返回-1,errno的值如下:
	EACCESS:没有权限
	EEXIST:信号量集已经存在,无法创建
	EIDRM:信号量集已经删除
	ENOENT:信号量集不存在,同时semflg没有设置IPC_CREAT标志
	ENOMEM:没有足够的内存创建新的信号量集
	ENOSPC:超出限制
@key:整数或者IPC_PRIVATE(0),信号量的标识。
	IPC_PRIVATE,表示私有的,意味信号量只能用于亲缘进程通信
@nsems:信号量集的个数,换句话来说,semget创建的信号量集id,可以控制nsems个资源的访问和释放
@semflg:九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的;
如果单独使用IPC_CREAT,则shmget()要么返回一个新创建的信号量的标识符,要么返回具有相同关键字值的标识符;
如果IPC_EXCL和IPC_CREAT一起使用,如果信号量已经存在则返回一个失败值-1,否则创建一个新的信号量,IPC_EXCL单独使用是没有用处的。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);

@semop:实现信号量的资源操作(P和V)
@int :成功返回相应的信号量标识符,失败返回-1
@semid:信号量集标识符
@sops:指向进行操作的信号量集结构体数组的首地址
	struct sembuf
	{
	     unsigned short sem_num;  /* semaphore number */
	     short sem_op;/* semaphore operation */
	     short sem_flg;/* operation flags */
	}
	sem_op:它的值可为正数、负数、0。正数表示释放资源操作(V操作),负数表示要请求资源访问的操作(P操作),0表示等待可用资源。
	sem_flg:它的值可为0、IPC_NOWAIT、SEM_UNDO。IPC_NOWAIT表示该操作为非阻塞操作,SEM_UNDO表示当进程退出的时候会还原该进程的信号量操作可以避免死锁。
@nsops:进sops结构变量的个数,需大于或等于1。一般为1,只完成对一个信号量的操作。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, union semun arg)

@semctl函数:控制信号量(&删除)
@int:成功返回非负整数,失败返回-1
@semid:信号量集标识符
@semnum:信号量集数组上的下标,表示某一个信号量
@cmd:操作类型,可取值IPC_STAT或者IPC_SET或者IPC_RMID
	IPC_STAT:从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中
	IPC_SET:设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值
	IPC_RMID:从内核中删除信号量集合
	GETALL:从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中
	GETNCNT:返回当前等待资源的进程个数
	GETPID:返回最后一个执行系统调用semop()进程的PID
	GETVAL:返回信号量集合内单个信号量的值
	GETZCNT:返回当前等待100%资源利用的进程个数
	SETALL:与GETALL正好相反
	SETVAL:用联合体中val成员的值设置信号量集合中单个信号量的值
@arg:输出输入信号量状态
	union semun {
	   short val;          /*SETVAL用的值*/
	   struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/
	   unsigned short* array; /*SETALL、GETALL用的数组值*/
	   struct seminfo *buf;   /*为控制IPC_INFO提供的缓存*/
	} arg;

三:实现父子进程分别向屏幕打印“AA”“BB”

/*
实现父子进程分别向屏幕打印“AA”“BB”
*/

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

using namespace std;
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

//需要自定义
union semun
{
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;
};

void Print(int semid, char c)
{
    struct sembuf sf;
    sf.sem_num = 0;
    sf.sem_flg = SEM_UNDO;
	while (true)
	{
		sf.sem_op = -1;
		semop(semid, &sf, 1);	//P操作请求资源
		printf("%c", c);
		fflush(stdout);
		sleep(1);
		printf("%c", c);
		fflush(stdout);
		sf.sem_op = 1;
		semop(semid, &sf, 1);	//V操作释放资源
	}
}

int main(int argc, char *argv[])
{
    int semid = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
    if (semid == -1)
    {
    	ERR_EXIT("semget");
    }

    //初始化0信号量的val值为1
    union semun un;
    un.val = 1;
	if(semctl(semid, 0, SETVAL, un) < 0)
	{
		ERR_EXIT("semctl");
	}

    pid_t pid = fork();
    if (pid < 0)
    	ERR_EXIT("fork");
    else if (pid == 0)
	{
    	Print(semid, 'B');
	}
    else
    {
    	Print(semid, 'A');
    }

    //删除该信号量
    sleep(5);
	if(semctl(semid, 0, IPC_RMID) < 0)
	{
		ERR_EXIT("semctl");
	}
    return 0;
}
/*
结果:
root@epc:/home/share/project/test/linux/demo# ./server 
AABBAABBAABBAABBAABBA^C
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统提供了各种系统调用API用于进程之间的通信:    无名管道PIPE    命名管道FIFO    消息队列    共享内存    信号量    文件锁    信号signal....其中还包括system V和POSIX 两种接口标准,除此之外,Linux系统自身还扩展了自己的一套API接口用于进程间通信,比如signalfd、timerfd、eventfd等。本视频教程为《Linux系统编程》第05期,本期课程将会带领大家学习Linux下将近15种进程间通信IPC工具的使用,了解它们的通信机制、编程实例、使用场景、内核中的实现以及各自的优缺点。本课程会提供PDF版本的PPT课件和代码,学员购买课程后可到课程主页自行下载嵌入式自学路线指导图:------------------------------------------------------------------------------------------------------                   《嵌入式工程师自我修养》嵌入式自学系列教程                                          作者:王利涛------------------------------------------------------------------------------------------------------一线嵌入式工程师精心打造,嵌入式学习路线六步走: 第 1 步:Linux三剑客零基础玩转Linux+UbuntuGit零基础实战:Linux开发技能标配vim从入门到精通基础篇:零基础学习vim基本命令vim从入门到精通定制篇:使用插件打造嵌入式开发IDEmakefile工程实践基础篇:从零开始一步一步写项目的Makefilemakefile工程实践第2季:使用Autotools自动生成Makefile软件调试基础理论printf打印技巧Linux内核日志与打印使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境第 2 步:C语言嵌入式Linux高级编程第1期:C语言进阶学习路线指南第2期:计算机架构与ARM汇编程序设计第3期:程序的编译、链接和运行原理第4期:堆栈内存管理第6期:数据存储与指针第7期:嵌入式数据结构与Linux内核的OOP思想第8期:C语言的模块化编程第9期:CPU和操作系统入门      搞内核驱动开发、光会C语言是不行的!      你还需要学习的有很多,包括:计算机体系架构、ARM汇编、程序的编译链接运行原理、CPU和操作系统原理、堆栈内存管理、指针、linux内核中的面向对象思想、嵌入式系统架构、C语言的模块化编程.....第 3 步:Linux系统编程第00期:Linux系统编程入门第01期:揭开文件系统的神秘面纱第02期:文件I/O编程实战第03期:I/O缓存与内存映射第04期:打通进程与终端的任督二脉第05期:进程间通信-------------------we are here!‍    第 4 步:Linux内核编程‍    练乾坤大挪移,会不会九阳神功,是一道坎。搞驱动内核开发,懂不懂内核也是一道坎。第 5 步:嵌入式驱动开发    芯片原理、datasheet、硬件电路、调试手段、总线协议、内核机制、框架流程....第 6 步:项目实战    嵌入式、嵌入式人工智能、物联网、智能家居...

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值