Linux C 信号量

2023-05-16

文章目录

  • 1、信号量的概念
    • 1.1、二元信号量
  • 2、函数介绍
    • 2.1、semget函数
    • 2.2、semctl函数
    • 2.3、semop函数
  • 3、示例代码
  • 4、其他操作

1、信号量的概念

用于协调多个进程(包括但不限于父子进程)对共享数据对象的读/写。它不以传送数据为目的,主要是用来保护共享资源,保证共享资源在一个时刻只有一个进程独享。

1.1、二元信号量

信号量是一个特殊的变量,只允许进程对它进行等待信号和发送信号操作。最简单的信号量是取值0和1的二元信号量,这是信号量最常见的形式,1表示可以访问,0表示加锁

2、函数介绍

Linux中提供了一组函数用于操作信号量,程序中需要包含以下头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

2.1、semget函数

semget函数用来获取或创建信号量

typedef unsigned int key_t
int semget(key_t key, int nsems, int semflg);
参数:
	key:是信号量的键值,是信号量在系统中的编号(一般用十六进制表示)
	nsems:是创建信号量集中信号量的个数,该参数只在创建信号量集时有效,这里固定填1。
	sem_flags:是一组标志,如果希望信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。如果没有设置IPC_CREAT标志并且信号量不存在,就会返错(errno的值为2,No such file or directory)

返回值:
	成功:返回信号量集的标识
	失败:-1

示例代码:
1)获取键值为0x5000的信号量,如果该信号量不存在,就创建它,代码如下:
int semid=semget(0x5000,1,0640|IPC_CREAT);

2)获取键值为0x5000的信号量,如果该信号量不存在,返回-1,errno的值被设置为2,代码如下:
int semid= semget(0x5000,1,0640)

2.2、semctl函数

该函数用来控制信号量(常用于设置信号量的初始值和销毁信号量

int semctl(int semid, int sem_num, int command, ...);
参数:
	semid:		semget函数返回值
	sem_num:	是信号量集数组上的下标,表示某一个信号量,填0
	cmd:		是对信号量操作的命令种类,常用的有以下两个:
	IPC_RMID:销毁信号量,不需要第四个参数;
	SETVAL:初始化信号量的值(信号量成功创建后,需要设置初始值),这个值由第四个参数决定。

第四参数是一个自定义的共同体,如下:
// 用于信号灯操作的共同体。
  union semun
  {
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
  };

示例:
1)销毁信号量。
  semctl(semid,0,IPC_RMID);
2)初始化信号量的值为1,信号量可用。
  union semun sem_union;
  sem_union.val = 1;
  semctl(semid,0,SETVAL,sem_union);

2.3、semop函数

该函数有两个功能:1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0,这个过程也称之为等待锁;2)把信号量的值置为1,这个过程也称之为释放锁。

int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:
	semid:semget函数返回的信号量标识
	sops:是一个结构体
struct sembuf
{
  short sem_num;   // 信号量集的个数,单个信号量设置为0。
  short sem_op;    // 信号量在本次操作中需要改变的数据:-1-等待操作;1-发送操作。
  short sem_flg;   // 把此标志设置为SEM_UNDO,操作系统将跟踪这个信号量。
                   // 如果当前进程退出时没有释放信号量,操作系统将释放信号量,避免资源被死锁。
};
	nsops:是操作信号量的个数,即sops结构变量的个数,设置它的为1(只对一个信号量的操作)

示例:
1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id, &sem_b, 1);

2)把信号量的值置为1struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id, &sem_b, 1);

3、示例代码

这段代码从严格来说是错误的,因为我没有加错误处理,这样子写主要是为了理解,大家看一下加深理解就好,

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

union semun  // 用于信号量操作的共同体。
{
    int val;
    struct semid_ds *buf;
    unsigned short  *arry;
};

int main()
{
    int semid = semget(0x5000,1,0644|IPC_CREAT);            // 创建或获取信号量
    printf("semid:%d\n",semid);                             // 信号量id
    
    union semun sem_union;                                  // 设置信号量初始值
    sem_union.val = 1;
    semctl(semid,0,SETVAL,sem_union);

    int value = semctl(semid,0,GETVAL);                     // 获取当前信号量的值
    printf("value:%d\n",value);

    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;   
    semop(semid,&sem_b,1);                                 // 相当于加锁操作
                                                           // 设置完之后信号量值就变成0了,标识持有锁
    int value1 = semctl(semid,0,GETVAL);                   // 获取一下当前信号量值,当前值就是0
    printf("value1:%d\n",value1);

    sem_b.sem_num = 0; 
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;   
    semop(semid,&sem_b,1);                                  // 释放锁操作
                                                            // 设置完,信号量值为1

    int value2 = semctl(semid,0,GETVAL);                    // 获取当前信号量值,当前值就是1
    printf("value1:%d\n",value2);

    return 0;
}

4、其他操作

1、用ipcs -s可以查看系统的信号量,内容有键值(key),信号量编号(semid),创建者(owner),权限(perms),信号量数(nsems)。

2、用ipcrm sem 信号量编号,可以手工删除信号量
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux C 信号量 的相关文章

  • 正则表达式删除块注释也删除 * 选择器

    我正在尝试使用 bash 从 css 文件中删除所有块注释 我有以下 sed 命令的正则表达式 sed r s w s w d 这可以很好地去除块注释 例如 This is a comment this is another comment
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 在汇编中使用 printf 会导致管道传输时输出为空,但可以在终端上使用

    无输出 https stackoverflow com questions 54507957 printf call from assembly do not print to stdout即使在终端上 当输出不包含换行符时也有相同的原因
  • 如何才能将 TCP 连接返回到同一端口?

    机器是 RHEL 5 3 内核 2 6 18 有时我在 netstat 中注意到我的应用程序有连接 建立了 TCP 连接本地地址 and 国外地址是一样的 其他人也报告了同样的问题 症状与链接中描述的相同 客户端连接到本地运行的服务器的端口
  • grep 排除文件的数组参数

    我想从我的文件中排除一些文件grep命令 为此我使用参数 exclude excluded file ext 为了更容易阅读 我想使用包含排除文件的 bash 数组 EXCLUDED FILES excluded file ext 然后将
  • ssh 连接超时

    我无法在 git 中 ssh 到 github bitbucket 或 gitlab 我通常会收到以下错误消息 如何避免它 输出 ssh T email protected cdn cgi l email protection i ssh
  • linux下无法创建僵尸进程

    嗯 我有一个奇怪的问题 我无法在我的项目中创建僵尸进程 但我可以在其他文件中创建僵尸进程 有简单的说明 int main if fork 0 printf Some instructions n else sleep 10 wait 0 r
  • 如何为 Linux 桌面条目文件指定带有相对路径的图标?

    对于我的一个 Linux 应用程序 我有应用程序二进制文件 一个 launcher sh 脚本 针对 LD LIBRARY PATH 和一个 desktop 文件 所有这些都位于同一文件夹中 我想使用图标的相对路径而不是绝对路径 我试过了
  • 在 Linux 上以编程方式设置 DNS 名称服务器

    我希望能够通过我的 C C 程序为 Linux 上的 DNS 名称服务器添加 IP 地址 我在一个带有只读 etc resolv conf 的嵌入式平台上 这意味着我不能简单地将 nameserver xxx xxx xxx xxx 行添加
  • linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误

    我正在安装Sharp用于使用 package json 的 Nodejs 项目的 docker 映像上的映像压缩包 当我创建容器时 我收到有关 Sharp 包的以下错误 app node modules sharp lib libvips
  • 如何在linux中以编程方式获取dir的大小?

    我想通过 C 程序获取 linux 中特定目录的确切大小 我尝试使用 statfs path struct statfs 但它没有给出确切的大小 我也尝试过 stat 但它返回任何目录的大小为 4096 请建议我如何获取 dir 的确切大小
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • 使用循环在 C 中管道传输两个或多个 shell 命令

    我正在尝试执行ls wc l通过 C 语言程序 而不是使用命令行 这是我当前的工作代码 int main int pfds 2 pipe pfds pid t pid fork if pid 0 The child process clos
  • 在 Mono 上运行 .Net MVC5 应用程序

    我正在 Windows 上的 Visual Studio 2013 中开发 Net 4 5 1 MVC5 应用程序 现在我想知道 是否可以在Linux Ubuntu 12 04 上运行这个应用程序 可以使用OWIN吗 Owin 可以自托管运
  • Bash - 在与当前终端分开的另一个终端中启动命令的新实例

    我有一个简单的 bash 脚本 test sh 设置如下 bin bash args if args 0 check capture then watch n 1 ls lag home user capture0 watch n 1 ls
  • 与 pthread 的进程间互斥

    我想使用一个互斥体 它将用于同步对两个不同进程共享的内存中驻留的某些变量的访问 我怎样才能做到这一点 执行该操作的代码示例将非常感激 以下示例演示了 Pthread 进程间互斥体的创建 使用和销毁 将示例推广到多个进程作为读者的练习 inc
  • 如何在 Linux 中使用 C 语言使用共享内存

    我的一个项目有点问题 我一直在试图找到一个有据可查的使用共享内存的例子fork 但没有成功 基本上情况是 当用户启动程序时 我需要在共享内存中存储两个值 当前路径这是一个char and a 文件名这也是char 根据命令参数 启动一个新进
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • 绕过 dev/urandom|random 进行测试

    我想编写一个功能测试用例 用已知的随机数值来测试程序 我已经在单元测试期间用模拟对其进行了测试 但我也希望用于功能测试 当然不是全部 最简单的方法是什么 dev urandom仅覆盖一个进程 有没有办法做类似的事情chroot对于单个文件并
  • 如何在 *nix 中登录时运行脚本?

    我知道我曾经知道如何做到这一点 但是 如何在 unix 中登录时运行脚本 bash 可以 From 维基百科 Bash http en wikipedia org wiki Bash 28Unix shell 29 当 Bash 启动时 它

随机推荐