Linux IPC实践(11) --System V信号量(1)

2023-05-16

信号量API

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);

semget

int semget(key_t key, int nsems, int semflg);

创建/访问一个信号量集

参数:

   key: 信号集键(key)

   nsems:信号集中信号量的个数

   semflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志一致

返回值:成功返回一个非负整数,即该信号集的标识码;失败返回-1;

   此时创建的信号量集中的每一个信号量都会有一个默认值: 0, 如果需要更改该值, 则需要调用semctl函数->更改初始值;

/** 示例1: 封装一个创建一个信号量集函数 
该信号量集包含1个信号量;
权限为0666
**/
int sem_create(key_t key)
{
    int semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);
    if (semid == -1)
        err_exit("sem_create error");
    return semid;
}
/** 示例2: 打开一个信号量集
nsems(信号量数量)可以填0,
semflg(信号量权限)也可以填0, 表示使用默认的权限打开
**/
int sem_open(key_t key)
{
    int semid = semget(key, 0, 0);
    if (semid == -1)
        err_exit("sem_open error");
    return semid;
}

shmctl

int semctl(int semid, int semnum, int cmd, ...);

控制信号量集

参数

   semid:由semget返回的信号集标识码

   semnum:信号集中信号量的序号(注意: 从0开始The semaphores in a set are numbered starting at 0.)

   cmd:将要采取的动作(常用取值如下)


   如果该函数需要第四个参数(有时是不需要第四个参数的, 取决于cmd的取值), 则程序中必须定义如下的联合体:

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;  /* Buffer for IPC_INFO (Linux-specific)*/
};
//struct semid_ds : Linux内核为System V信号量维护的数据结构
struct semid_ds
{
    struct ipc_perm sem_perm;  /* Ownership and permissions */
    time_t          sem_otime; /* Last semop time */
    time_t          sem_ctime; /* Last change time */
    unsigned long   sem_nsems; /* No. of semaphores in set */
};
/** 示例1: 将信号量集semid中的第一个信号量的值设置成为value(SETVAL)
注意: semun联合体需要自己给出(从man-page中拷贝出来即可)
**/
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;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};
int sem_setval(int semid, int value)
{
    union semun su;
    su.val = value;
    if (semctl(semid, 0, SETVAL, su) == -1)
        err_exit("sem_setval error");
    return 0;
}
/** 示例2: 获取信号量集中第一个信号所关联的值(GETVAL)
注意: 此时第四个参数可以不填, 而信号量所关联的值可以通过semctl的返回值返回(the value of semval.)
**/
int sem_getval(int semid)
{
    int value = semctl(semid, 0, GETVAL);
    if (value == -1)
        err_exit("sem_getval error");
    return value;
    return 0;
}
/** 示例3: 删除一个信号量集(注意是删除整个集合)
	IPC_RMID  Immediately  remove(立刻删除)  the  semaphore  set,  awakening  all  processes blocked in semop(2) calls on the set (with an error return and errno set to  EIDRM)[然后唤醒所有阻塞在该信号量上的进程]. The  argument  semnum  is ignored[忽略第二个参数].
**/
int sem_delete(int semid)
{
    if (semctl(semid, 0, IPC_RMID) == -1)
        err_exit("sem_delete error");
    return 0;
}

//测试代码
int main(int argc,char *argv[])
{
    int semid = sem_create(0x1234);	//创建一个信号量集
    sem_setval(semid, 500);			//设置值
    cout << sem_getval(semid) << endl;	//获取值
    sleep(10);
    sem_delete(semid);		//删除该集合
}
/**示例4: 获取/设置信号量的权限
注意:一定要设定struct semid_ds结构体, 以指定使用semun的哪个字段
**/
int sem_getmode(int semid)
{
    union semun su;

    // 注意: 下面这两行语句一定要设定.
    // (告诉内核使用的semun的哪个字段)
    struct semid_ds sd;
    su.buf = &sd;
    //
    if (semctl(semid, 0, IPC_STAT, su) == -1)
        err_exit("sem_getmode error");
    printf("current permissions is: %o\n", su.buf->sem_perm.mode);
    return 0;
}
int sem_setmode(int semid, char *mode)
{
    union semun su;
    // 注意: 下面这两行语句一定要设定.
    // (告诉内核使用的semun的哪个字段)
    struct semid_ds sd;
    su.buf = &sd;
    //
    sscanf(mode, "%o", (unsigned int *)&su.buf->sem_perm.mode);

    if (semctl(semid, 0, IPC_SET, su) == -1)
        err_exit("sem_setmode error");
    return 0;
}

semop

int semop(int semid, struct sembuf *sops, unsigned nsops);

   用来操纵一个信号量集, 以实现P,V操作

参数:

   semid:是该信号量的标识码,也就是semget函数的返回值

   sops:是个指向一个结构数组(如果信号量集中只有一个信号量的话, 只有一个结构体也可)的指针

   nsops:所设置的信号量个数(如果nsops>1话, 需要将sops[第二个参数]设置成为一个结构数组, 具体参考Man-Page给出的示例代码), 第三个参数其实也指出第二个参数所表示对象的个数;

//sembuf结构体
struct sembuf
{
    unsigned short sem_num;  /*semaphore number:信号量的编号(从0开始)*/
    short          sem_op;   /* semaphore operation(+1, 0, -1) */
    short          sem_flg;  /* operation flags: 常用取值为SEM_UNDO(解释见下) */
};

   sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值,一个是“-1”,也就是P操作,等待信号量变得可用;另一个是“+1”,也就是V操作,发出信号量已经变得可用, 该参数还可以等于0, 表示进程将阻塞直到信号量的值等于0;

   sem_flg有三个取值: SEM_UNDO(在进程结束时, 将该进程对信号量的操作复原[即:取消该进程对信号量所有的操作], 推荐使用), IPC_NOWAIT(非阻塞)或0(默认操作, 并不撤销操作);

/** 示例: P,V操作封装 
**可以将sembuf的第三个参数设置为IPC_NOWAIT/0, 以查看程序的状态的变化
**/
int sem_P(int semid)
{
    struct sembuf sops = {0, -1, SEM_UNDO};
    if (semop(semid, &sops, 1) == -1)
        err_exit("sem_P error");
    return 0;
}
int sem_V(int semid)
{
    struct sembuf sops = {0, +1, SEM_UNDO};
    if (semop(semid, &sops, 1) == -1)
        err_exit("sem_V error");
    return 0;
}

/** 信号量综合运用示例:
编译完成之后, 直接运行./semtool, 程序将打印该工具的用法;
下面的这些函数调用, 只不过是对上面所封装函数的稍稍改动, 理解起来并不困难;
**/
//semtool.cpp
#include "Usage.h"

int main(int argc,char *argv[])
{
    int opt = getopt(argc, argv, "cdpvs:gfm:");
    if (opt == '?')
        exit(EXIT_FAILURE);
    else if (opt == -1)
    {
        usage();
        exit(EXIT_FAILURE);
    }

    key_t key = ftok(".", 's');
    int semid;
    switch (opt)
    {
    case 'c':
        sem_create(key);
        break;
    case 'd':
        semid = sem_open(key);
        sem_delete(semid);
        break;
    case 'p':
        semid = sem_open(key);
        sem_P(semid);
        sem_getval(semid);
        break;
    case 'v':
        semid = sem_open(key);
        sem_V(semid);
        sem_getval(semid);
        break;
    case 's':
        semid = sem_open(key);
        sem_setval(semid, atoi(optarg));
        sem_getval(semid);
        break;
    case 'g':
        semid = sem_open(key);
        sem_getval(semid);
        break;
    case 'f':
        semid = sem_open(key);
        sem_getmode(semid);
        break;
    case 'm':
        semid = sem_open(key);
        sem_setmode(semid, argv[2]);
        sem_getmode(semid);
        break;
    default:
        break;
    }

    return 0;
}
//Usage.h
#ifndef USAGE_H_INCLUDED
#define USAGE_H_INCLUDED

#include <iostream>
#include <string>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <time.h>
#include <errno.h>
#include <mqueue.h>
using namespace std;
inline void err_quit(std::string message);
inline void err_exit(std::string message);

void usage()
{
    cerr << "Usage:" << endl;
    cerr << "./semtool -c        #create" << endl;
    cerr << "./semtool -d        #delte" << endl;
    cerr << "./semtool -p        #signal" << endl;
    cerr << "./semtool -v        #wait" << endl;
    cerr << "./semtool -s <val>  #set-value" << endl;
    cerr << "./semtool -g        #get-value" << endl;
    cerr << "./semtool -f        #print-mode" << endl;
    cerr << "./semtool -m <mode> #set-mode" << endl;
}

int sem_create(key_t key)
{
    int semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);
    if (semid == -1)
        err_exit("sem_create error");
    return semid;
}
int sem_open(key_t key)
{
    int semid = semget(key, 0, 0);
    if (semid == -1)
        err_exit("sem_open error");
    return semid;
}

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;  /* Buffer for IPC_INFO (Linux-specific) */
};

int sem_getmode(int semid)
{
    union semun su;

    // 注意: 下面这两行语句一定要设定.
    // (告诉内核使用的semun的哪个字段)
    struct semid_ds sd;
    su.buf = &sd;
    //
    if (semctl(semid, 0, IPC_STAT, su) == -1)
        err_exit("sem_getmode error");
    printf("current permissions is: %o\n", su.buf->sem_perm.mode);
    return 0;
}
int sem_setmode(int semid, char *mode)
{
    union semun su;
    // 注意: 下面这两行语句一定要设定.
    // (告诉内核使用的semun的哪个字段)
    struct semid_ds sd;
    su.buf = &sd;
    //
    sscanf(mode, "%o", (unsigned int *)&su.buf->sem_perm.mode);

    if (semctl(semid, 0, IPC_SET, su) == -1)
        err_exit("sem_setmode error");
    return 0;
}
int sem_getval(int semid)
{
    int value = semctl(semid, 0, GETVAL);
    if (value == -1)
        err_exit("sem_getval error");
    cout << "current value: " << value << endl;
    return value;
}
int sem_setval(int semid, int value)
{
    union semun su;
    su.val = value;
    if (semctl(semid, 0, SETVAL, su) == -1)
        err_exit("sem_setval error");
    return 0;
}

int sem_delete(int semid)
{
    if (semctl(semid, 0, IPC_RMID) == -1)
        err_exit("sem_delete error");
    return 0;
}

// 为了能够打印信号量的持续变化, 因此sem_flg我们并没用SEM_UNDO
// 但是我们推荐使用SEM_UNDO
int sem_P(int semid)
{
    struct sembuf sops = {0, -1, 0};
    if (semop(semid, &sops, 1) == -1)
        err_exit("sem_P error");
    return 0;
}
int sem_V(int semid)
{
    struct sembuf sops = {0, +1, 0};
    if (semop(semid, &sops, 1) == -1)
        err_exit("sem_V error");
    return 0;
}

inline void err_quit(std::string message)
{
    std::cerr << message << std::endl;
    exit(EXIT_FAILURE);
}
inline void err_exit(std::string message)
{
    perror(message.c_str());
    exit(EXIT_FAILURE);
}

#endif // USAGE_H_INCLUDED

附-Makefile

.PHONY: clean all 
CC = g++ 
CPPFLAGS = -Wall -g
BIN = semtool
SOURCES = $(BIN.=.cpp)
all: $(BIN)

%.o: %.c 
    $(CC) $(CPPFLAGS) -c $^ -o $@
main: main.o
    $(CC) $(CPPFLAGS) $^ -lrt -o $@

clean:
    -rm -rf $(BIN) *.o bin/ obj/ core

转载于:https://www.cnblogs.com/itrena/p/5926956.html

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

Linux IPC实践(11) --System V信号量(1) 的相关文章

  • 由于 abi::cxx11 符号导致的链接问题?

    我们最近收到一份报告 因为GCC 5 1 libstdc 和双 ABI http gcc gnu org onlinedocs libstdc manual using dual abi html 它似乎Clang 不知道 GCC 内联名称
  • 如何从程序内部获取指向程序的特定可执行文件部分的指针? (也许是诽谤)

    我在 Linux 环境中 需要编写一个程序来检索放置在其可执行文件的某个部分中的一些数据 那么 如何从程序内部获取指向程序某个部分 通过其名称 的指针呢 我知道可以使用elf getdata 将节的索引作为参数传递给 get 和Elf Da
  • Linux下单个目录下文件过多会怎样?

    如果一个目录中有大约 1 000 000 个单独的文件 大部分大小为 100k 其中没有其他目录和文件 是否会以任何其他可能的方式降低效率或产生缺点 ARG MAX 会对此提出异议 例如 rm rf 在目录中时 会说 参数太多 想要执行某种
  • GCC 详细模式输出解释

    我是 Linux 新手 谁能向我解释一下我的 hello world 程序的以下详细模式输出 另外 这些文件是做什么用的crt1 o crti o crtend o crtbegin o and crtn o and lc and lgcc
  • Linux 中的 Windows NAmed Pipes 替代品

    我们正在将现有的 Windows 代码移植到 Linux 我们使用 ACE 作为抽象层 我们使用 Windows 命名管道与多个客户端进行通信并执行重叠操作 linux 下这个相当于什么 我检查了linux命名管道 FIFO 但它们似乎只支
  • 在 MacOS 上构建需要 net461 的 dotnet SDK 项目的最简单方法

    我有一个 dotnet SDK sln and a build proj with
  • 如何在 Ubuntu/Linux 发行版中安装 Tesseract-OCR 3.03?

    我和一个朋友有兴趣为 CV 项目训练 tesseract OCR 引擎 我们尝试使用一些包装器 例如 PyTesser 和 pyocr 但结果目前不如我们需要的那么准确 因此 我们希望尝试训练超立方体以更好地实现我们的目的 即识别食品标签上
  • EULA 接受 Bash 脚本

    我有一个尝试安装垃圾箱的脚本 除了 bin 在 more 中打开 EULA 之外 一切正常 在脚本再次开始并自行完成安装之前 您必须手动 ctrl c 退出此 more 实例 因为这更多的是逃离 shell 所以脚本在打开后不知道要运行什么
  • 使用 .htaccess 启用 PHP 短标签

    我在自己的 Centos 服务器上设置了 Apache 并具有多个虚拟 Web 服务器 并且我希望仅为位于以下位置的其中一个 Web 服务器启用 PHP 短标记 var www ostickets html 我可以通过添加成功启用短标签sh
  • SIGHUP 用于重新加载配置

    根据signal 7 SIGHUP用于检测控制终端的挂起或控制进程的死亡 然而 我遇到过很多 OSS 守护进程 服务 其中SIGHUP用于启动配置的重新加载 这里有一些例子 hostapd sshd snort etc 这是实现重新加载的标
  • X 按键/释放事件捕获,与焦点窗口无关

    我想记录所有传入的按键事件 无论哪个窗口处于焦点状态或指针位于何处 我编写了一个示例代码 它应该捕获当前焦点窗口的按键事件 include
  • 使用 hcitool 扫描低功耗蓝牙?

    当我运行此命令时 BLE 设备扫描仅持续 5 秒 sudo timeout 5s hcitool i hci0 lescan 输出显示在终端屏幕中 但是 当我将输出重定向到文件以保存广告设备的地址时 每次运行该命令时 我都会发现该文件是空的
  • 在 MacO 和 Linux 上安装 win32com [重复]

    这个问题在这里已经有答案了 我的问题很简单 我可以安装吗win32com蟒蛇API pywin32特别是 在非 Windows 操作系统上 我一直在Mac上尝试多个版本pip install pywin32 都失败了 下面是一个例子 如果你
  • ARM 的内核 Oops 页面错误错误代码

    Oops 之后的错误代码给出了有关 ARM EX 中的恐慌的信息 Oops 17 1 PREEMPT SMP在这种情况下 17 给出了信息 在 x86 中它代表 bit 0 0 no page found 1 protection faul
  • 在bash中用其他文件过滤一个文件

    我有一个带有数字的文件 例如 cat file 31038467 32048169 33058564 34088662 35093964 31018168 31138061 31208369 31538163 31798862 和其他例如
  • Linux 阻塞与非阻塞串行读取

    I have 这段代码 https stackoverflow com questions 6947413 how to open read and write from serial port in c用于在Linux中从串行读取 但我不
  • C# - OPC-UA 服务器应用程序尚未在 Linux 计算机中创建 PKI 证书

    当我跑步时OPC UA serverWindows 机器中的 C 应用程序 然后 OPC UA 服务器已创建证书路径C ProgramData OPC Foundation pki own 并在此路径中生成一些证书 但是当我在中安装 OPC
  • 在Linux中将日期附加到文件名

    我想在文件名旁边添加日期 somefile txt 例如 somefile 25 11 2009 txt 或 somefile 25Nov2009 txt 或任何类似的内容 也许脚本或终端窗口中的某些命令可以执行 我正在使用Linux Ub
  • bash "&" 不打印 "[1]+ Done "

    我在 bashrc 中调用一个脚本来打印打开终端时收到的新消息数 我希望该调用在访问网络时是非阻塞的 有时需要几秒钟 这意味着我无法使用终端直到完成 但是如果我输入 mailcheck 在我的 bashrc 中 它工作正常 但然后打印一个空
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当

随机推荐

  • 深度学习数学基础

    机器学习简介 xff1a 特征向量 目标函数 机器学习分类 xff1a 有监督学习 xff1a 分类问题 xff08 如人脸识别 字符识别 语音识别 xff09 回归问题 无监督学习 xff1a 聚类问题 数据降维 强化学习 xff1a 根
  • zabbix监控Linux服务器丢包率

    http www ttlsa com zabbix zabbix simple checks 这个文章看了 xff0c 还没有实践 1 先创建监控项 xff0c 键值如下 icmppingloss lt 121 131 24 39 gt l
  • 重装@angular/cli reason: write EPROTO 139955972261696:error:1408F10B:SSL routines:ssl3_get_record:wron...

    前几天不小心卸载了 angular 64 cli 然后重装的时候发现 xff0c 一直报错 如下 xff1a 64 ln622653 npm install g 64 angular cli npm ERR code EPROTO npm
  • Outlook2016删不掉主账户的解决方法

    控制面板 gt 账户 gt 邮件把配置文件删了 前两项和Outlook内部打开账户选项一样没用 进第三个 重启Oulook的时候会提示重新建一个配置 就OK了 转载于 https www cnblogs com haimingpro p 6
  • 新版新概念英语1-4册(英音+美音)MP3打包下载

    新版新概念英语第一册MP3 美音 新版新概念英语第一册MP3 英音 新版新概念英语第一册PDF 课文 新版新概念英语第二册MP3 美音 新版新概念英语第二册MP3 英音 新版新概念英语第二册PDF 课文 新版新概念英语第三册MP3 美音 新
  • linux远程windows无法输入,XRDP在Windows下用远程桌面连接,键盘失效有关问题

    XRDP在Windows下用远程桌面连接 xff0c 键盘失效问题 很久没上这个博客了 xff0c 最近在做虚拟化方面的东西 xff0c 有个需求是通过windows远程连接Linux桌面 xff0c 采用的是xrdp 安装和使用xrdp都
  • 3367 【模板】并查集

    题目描述 如题 xff0c 现在有一个并查集 xff0c 你需要完成合并和查询操作 输入输出格式 输入格式 xff1a 第一行包含两个整数N M xff0c 表示共有N个元素和M个操作 接下来M行 xff0c 每行包含三个整数Zi Xi Y
  • MySQL优化之my.conf配置详解

    最近项目不太忙 xff0c 所以有时间静心来研究下mysql的优化 xff0c 对于MySQL的设置是否合理优化 xff0c 直接影响到网站的速度和承载量 xff01 同时 xff0c MySQL也是优化难度最大的一个部分 xff0c 不但
  • NPM全局安装软件包时解决EACCES权限错误

    NPM全局安装软件包时解决EACCES权限错误 Resolving EACCES permissions errors when installing packages globally npm WARN checkPermissions
  • 阿里云学生服务器认证条件详解与选择教程

    简介 xff1a 本文汇总学生购买阿里云服务器以及其它云产品优惠 xff0c 阿里云的云翼计划 xff0c 是阿里云针对在校学生扶持的一项优惠活动 xff0c 只需9元即可购买阿里云服务器 xff0c 而且云服务器配置不低 xff0c 足够
  • deepin系统

    https www uc23 net xinwen 76259 html 据介绍 xff0c 深度操作系统 xff08 deepin xff09 自 2015 年开始 xff0c 就放弃基于 Ubuntu 作为上游 xff0c 选择 Ubu
  • Linux 大文件日志快速定位错误或者异常的位置

    1 得到错误日志或者异常日志的行号 cat n test log grep 34 error 34 cat n test log grep 34 exception 34 2 通过位置往前往后查看日志详细 339563 can not cl
  • 《oracle正则表达式》摘抄+自理

    select from t test regexp A B 1 AAA 2 bbb 3 4 xff01 xff01 xff01 5 吴雁渡 6 12345 7 123AAbb存储 64 xff01 64 445BBC 1 REGEXP LI
  • ASP.NET Core 3.0 : 二十四. 配置的Options模式

    上一章讲到了配置的用法及内部处理机制 xff0c 对于配置 xff0c ASP NET Core还提供了一种Options模式 ASP NET Core 系列目录 一 Options的使用 上一章有个配置的绑定的例子 xff0c 可以将配置
  • 区分柱状图(条形图)和直方图

    柱状图 61 条形图 柱状图一般用于描述离散型分类数据的对比每根柱子宽度固定 xff0c 柱子之间会有间距横轴变量可以任意排序 直方图 直方图一般用于描述连续型数据的分布关系每根柱子宽度可以不一样 xff0c 且一般没有间距横轴变量有一定顺
  • Latex公式字母加粗

    在Latex 中 xff0c 公式字母加粗用语法 xff1a boldsymbol 待添加的字母 xff0c 如 xff1a boldsymbol bold 61 frac 1 boldsymbol w s t boldsymbol x 4
  • [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web app...

    问题 启动tomcat 就一直卡在了这里 继续往上查看日志 解决方法 xff1a 转载于 https www cnblogs com chenyanlong p 10699434 html
  • ccf 画图

    问题描述 试题编号 xff1a 201409 2试题名称 xff1a 画图时间限制 xff1a 1 0s内存限制 xff1a 256 0MB问题描述 xff1a 问题描述 在一个定义了直角坐标系的纸上 xff0c 画一个 x1 y1 到 x
  • Pigx官方文档地址

    https www kancloud cn lengleng pig guide 949171 转载于 https www cnblogs com mengjianzhou p 11229623 html
  • Linux IPC实践(11) --System V信号量(1)

    信号量API include lt sys types h gt include lt sys ipc h gt include lt sys sem h gt int semget key t key int nsems int semf