进程间通信机制介绍

目录

无名管道pipe

有名管道fifo

信号signal

共享内存mmap

套接字socket


  1. 无名管道pipe

    1. 无名管道特点:
      1. 只能用于具有亲缘关系的进程之间的通信(父子进程,兄弟进程.)
      2. 单工的通讯方式,具有固定的读端和写端(一端读一端写,程序实现设计好)
      3. 无名管道创建时会返回两个文件描述符,分别用于读写管道(数据自己读不能自己写)
      4. 管道可以用于大于2个进程共享
    2. 无名管道创建pipe
      1. #include<unistd.h>
      2. int pipe(int pfd[2]);
      3. 成功返回0,失败返回EOF
      4. pfd包含两个元素的整型数组,pdf[0]用于读管道,pfd[1]用于写管道
    3. 无名管道的读写特性:
      1. 读管道:
        1. 管道中有数据,read返回实际读到的字节数。
        2. 管道中无数据:
          1. 管道写端被全部关闭,read返回0 (好像读到文件结尾)
          2. 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)
      2. 写管道:
        1. 管道读端全部被关闭,进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
        2. 管道读端没有全部关闭:
          1. (1)管道已满,write阻塞。(管道大小64K)
          2. (2)管道未满,write将数据写入,并返回实际写入的字节数。
  2. 有名管道fifo

    1. 创建管道
      1. #include <sys/types.h>
      2. #include <sys/stat.h>int

      3. mkfifo(const char *filename, mode_t mode);

      4. open(const char *path, O_RDONLY);//1

      5. open(const char *path, O_RDONLY | O_NONBLOCK);//2

      6. open(const char *path, O_WRONLY);//3

      7. open(const char *path, O_WRONLY | O_NONBLOCK);//4

    2. 特点:

      1. 有名管道可以使非亲缘的两个进程互相通信

      2. 通过路径名来操作,在文件系统中可见,但内容存放在内存中

      3. 文件IO来操作有名管道

      4. 遵循先进先出规则

      5. 不支持leek操作

      6. 单工读写注意事项:

        1. 就是程序不能以O_RDWR(读写)模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程可以读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递

        2. 第二个参数中的选项O_NONBLOCK,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的

        3. 对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。

        4. 数据完整性,如果有多个进程写同一个管道,使用O_WRONLY方式打开管道,如果写入的数据长度小于等于PIPE_BUF(4K),那么或者写入全部字节,或者一个字节都不写入,系统就可以确保数据决不会交错在一起。

  3. 信号signal

    1. 信号机制
      1. 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
      2. linux内核通过信号通知用户进程,不同的信号类型代表不同的事件
      3. linux对早期的unix信号机制进行了扩展
      4. 进程对信号有不同的响应方式
        1. 缺省方式
        2. 忽略方式
        3. 捕捉方式
    2. 信号的产生
      1. 按键产生
      2. 系统调用函数产生(比如raise,kill)
      3. 硬件异常
      4. 命令行产生kill
      5. 软件条件(比如被0除,访问非法条件等)
    3. 常用信号

    4.  信号相关命令
      1. kill [-signal] pid默认发送SIGTERM-sig 可指定信号pid指定发送对象
      2. killall [-uuser | prog]prog指定进程名user指定用户名 
    5. 信号发送kill/raise
      1. #include<unistd.h>
      2. #include <signal.h>
      3. int kill(pid_t pid,int sig);
        1. 发送信号参数:
          1. pid:
            1. > 0:发送信号给指定进程
            2. = 0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程。
            3. < -1:取绝对值,发送信号给该绝对值所对应的进程组的所有组员。
            4. = -1:发送信号给,有权限发送的所有进程。
            5. sig:待发送的信号
      4. int raise(int sig);给自己发信号,等价于kill(getpid(), signo);
      5. 成功时返回0,失败时返回EOF
      6. pid 接收进程的进程号:0代表同组进程; -1代表所有进程
      7. sig 信号类型
    6. 定时器函数-alarm/pause
      1. #include<unistd.h>
      2. #include<signal.h>
      3. int alarm(unsigned int seconds);
        1. 成功返回上个定时器剩余时间,失败返回EOF
        2. seconds定时器的时间
        3. 一个进程中只能设定一个定时器,时间到时产生SIGALRM
      4. int pause(void);
        1. 进程一直阻塞,直到被信号中断
        2. 被信号中断后返回-1,errno为EINTR
      5. ualarm(循环发送)
      6. useconds_t ualarm(useconds_t uses, useconds_t interval);
        1. 以useconds为单位,第一额参数为第一次产生时间,第二个参数为间隔产生
      7. int setitimer(int which,const struct itimerval *new_value,struct itimerval *old_value);
        1. 功能:定时的发送alarm信号
        2. 参数:
          1. which:
            1. ITIMER_REAL:以逝去的时间递减,发送SIGALRM信号
            2. ITIMER_VIRTUAL:计算进程(用户模式)执行的时间。发送SIGVTALARM信号
            3. ITIMER_PROF:进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计算时间。发送SIGPROF信号
          2. new_value:负责设定timeout时间
          3. old_value:存放旧的timeout值,一般设定为NULL
          4. struct itimerval{
            1. struct timeval it_interval;//闹钟触发周期
            2. struct timeval it_value;//闹钟触发时间
          5. }
          6. struct timeval {
            1. time_ttv_sec;/* seconds */
            2. suseconds_t tv_usec;/* microseconds */
          7. };
    7. 信号的捕捉

      1. 信号捕捉过程:

        1. 定义新的信号的执行函数handle

        2. 使用signal/sigaction函数,把自定义的handle函数和指定的信号相关联。

          1. signal函数:

            1. typedef void (*sighandler_t)(int);

            2. sighandler_t signal(int signum, sighandler_t handler);

            3. 功能:捕捉信号执行自定义函数

            4. 返回值:成功时返回原先的信号处理函数,失败时返回SIG_ERR

            5. 参数:

              1. signo要设置的信号类型

              2. handler指定的信号处理函数:

                1. SIG_DFL代表缺省方式;

                2. SIG_IGN代表忽略信号;

        3. 系统建议使用sigaction函数,因为signal在不同类unix系统的行为不完全一样。

        4. sigaction函数:

          1. int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

          2. struct sigaction {

            1. void (*sa_handler)(int);

            2. void (*sa_sigaction)(int, siginfo_t *, void *);

            3. sigset_t sa_mask;

            4. int sa_flags;

            5. void (*sa_restorer)(void);

          3. }

          4. 参数:

            1. signum:处理的信号

            2. act,oldact:处理信号的新行为和旧的行为,是一个sigaction结构体。

            3. sigaction结构体成员定义如下:

              1. sa_handler:是一个函数指针,其含义与signal函数中的信号处理函数类似

              2. sa_sigaction:另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。

              3. sa_flags参考值如下:

                1. SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数

                2. SA_RESTART:使被信号打断的系统调用自动重新发起。

                3. SA_RESETHAND:信号处理之后重新设置为默认的处理方式。

                4. SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。

              4. re_restorer:是一个已经废弃的数据域

        5. 定时器的实现

        6. 使用SIGCHLD信号实现回收子进程

          1. SIGCHLD的产生条件

            1. 子进程终止时

            2. 子进程接收到SIGSTOP信号停止时

            3. 子进程处在停止态,接受到SIGCONT后唤醒时

      2. 信号集、信号的阻塞

        1. 有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况可以通过阻塞信号实现。

        2. 信号的阻塞概念:

          1. 信号的“阻塞”是一个开关动作,指的是阻塞信号被处理,但不是阻止信号产生

          2. 信号的状态:

            1. 信号递达(Delivery):实际信号执行的处理过程(3中状态:忽略,执行默认动作,捕获)

            2. 信号未决(Pending):从产生到递达之间的状态

      3. 信号集操作函数:

        1. sigset_set;  自定义信号集。 是一个32bit  64bit 128bit的数组。

        2. sigemptyset(sigset_t *set);清空信号集

        3. sigfillset(sigset_t *set);全部置1

        4. sigaddset(sigset_t *set,int signum); 将一个信号添加到集合中

        5. sigdelset(sigset_t *set,int signum);将一个信号从集合中移除

        6. sigismember(const sigset_t *set, int signum);判断一个信号是否在集合中

        7. 设定对信号集内的信号处理方式(阻塞或不阻塞)

          1. #include<signal.h>

          2. int sigprocmask(int how,const sigset_t *restrict set, sigset_t *restrict oset);

            1. 返回值:若成功则返回0,若出错则返回-1

            2. 首先,若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回

            3. 其次,若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字

            4. how可选用的值:(注意:不能阻塞SIGKILL和SIGSTOP信号)

            5. SIG_BLOCK:把参数set中的信号添加到信号屏蔽字中SIG_UNBLOCK:从信号屏蔽字中删除参数set中的信号SIG_SETMASK:把信号屏蔽字设置为参数set中的信号

      4. int pause(void);

        1. 进程一直阻塞,直到被信号中断,返回值:-1并设置errno为EINTR函数行为:

          1. 如果信号的默认处理动作是终止进程,则进程终止,pause函数没有机会返回。

          2. 如果信号的默认处理动作是忽略,进程继续处于挂起状态,pause函数不返回

          3. 如果信号的处理动作是捕捉,则调用完信号处理函数之后,pause返回-1。

          4.  pause收到的信号如果被屏蔽,那么pause就不能被唤醒

      5. int sigsuspend(const sigset_t *sigmask);

        1. 功能:将进程的屏蔽字替换为由参数sigmask给出的信号集,然后挂起进程的执行,参数:

          1. sigmask:希望屏蔽的信号

  4. 共享内存mmap

    1. 内存映射概念:
      1. 共享内存可以通过mmap()映射普通文件
      2. 使一个磁盘文件和内存中的一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write
    2. mmap优点:

      1. 实现了用户空间和内核空间高效的交互方式
      2. 函数定义:

        1. void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

      3. 函数功能:

        1. 创建共享内存映射函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED(((void *) -1)),

        2. 设置errno值参数说明:

          1. addr:指定要映射的内存地址,一般设置为NULL让操作系统自动选择合适的内存地址。

          2. length:必须>0。映射地址空间的字节数,它从被映射文件开头offset个字节开始算起。

          3. prot:指定共享内存的访问权限。可取如下几个值的可选:

            1. PROT_READ(可读)

            2.  PROT_WRITE(可写)

            3.  PROT_EXEC(可执行),

            4. PROT_NONE(不可访问)

          4. flags:

            1. 由以下几个常值指定:

              1. MAP_SHARED(共享的)

              2. MAP_PRIVATE(私有的)

              3. MAP_FIXED(表示必须使用start参数作为开始地址,如果失败不进行修正),其中,MAP_SHARED ,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。

              4. MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)fd:表示要映射的文件句柄。如果匿名映射写-1。offset:表示映射文件的偏移量,一般设置为0表示从文件头部开始映射。

      4. 注意事项:

        1. 创建映射区的过程中,隐含着一次对映射文件的读操作,将文件内容读取到映射区。

        2. 当MAP_SHARED时,要求:映射区的权限应<=文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误。当MAP_PRIVATE时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享。

        3. 映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。

        4. 用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误,指定0大小创建映射区,报非法参数错误(Invalid argument)

        5. 文件偏移量必须为0或者4K的整数倍(不是会报非法参数Invalid argument错误)

        6. 映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误,超出映射的内存大小报段错误

        7. mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。 

      5. mmap()映射的种类:

        1. 基于文件的映射

        2. 匿名映射适用于具有亲缘关系的进程之间

      6. 释放内存映射

        1. munmap函数

          1. int munmap(void *addr, size_t length);

          2. 返回值:成功返回0,失败返回-1,并设置errno值。

          3. 函数参数:

            1. addr:调用mmap函数成功返回的映射区首地址

            2. length:映射区大小(即:mmap函数的第二个参数)

      7. System V共享内存

        1. IPC(进程间通信的缩写)

          1. IPC对象包含:

            1. 共享内存

            2. 消息队列

            3. 信号灯集

          2. 每个IPC对象有唯一的ID,用key关联

          3. IPC对象创建后一直存在,直到被显式的删除

          4. ipcs/ipcrm

        2. 共享内存:

          1. 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝

          2. 共享内存在内核中创建,可被进程映射到用户空间,使用灵活

          3. 由于多个进程可同时访问共享内存,因此需要同步和互斥机制配合使用

        3. 共享内存使用步骤:

          1. 生成key

          2. 创建/打开共享内存

          3. 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

          4. 读写共享内存

          5. 撤销共享内存映射

          6. 删除共享内存对象

        4. ftok函数

          1. #include<sys/types.h>

          2. #include<sys/ipc.h>

          3. key_tftok(const char *path,int id);

            其中参数path是指定的文件名,这个文件必须是存在的而且可以访问的。id是子序号,它是一个8bit的整数。即范围是0~255。当函数执行成功,则会返回key_t键值,否则返回-1。在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值system

          4. V共享内存使用步骤:

            1. 1创建/打开共享内存

            2. 2映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

            3. 3读写共享内存

            4. 4撤销共享内存映射

            5. 5删除共享内存对象

              1. 查看共享内存命令ipcs共享内存创建– shmgetint shmget(key_t key, int size, int shmflg);

        5. 共享内存创建

          1. int shmget(key_t key, int size, int shmflg);

            成功返回共享内存id,失败返回EOF

            key和共享内存关联的key,IPC_PRIVATE或ftok生成

            shmflg共享内存标志位IPC_CREAT|0666

        6. 共享内存映射

          1. void*shmat(int shmid, const void *shmaddr, int shmflg);

          2. 第二个参数是映射后的地址一般写NULL,表示系统自动映射

          3. 第三参数标志位,一般写0,表示可读写,SHM_RDONLY表示只读

          4. 成功返回映射后地址,失败返回EOF

        7. 共享内存撤销

          1. int shmdt(void *shmaddr);

          2. 撤销后,内存地址不可再访问。

          3. 成功返回0,失败返回EOF

          4. 程序结束时自动撤销

        8. 共享内存控制

          1. int shmctl(int shmid, int cmd, struct shmid_ds *buf);

            1. 成功返回0,失败返回EOF

            2. shmid要操作的共享内存id

            3. cmd要执行的操作IPC_STAT IPC_SET IPC_RMID

            4. buf保存或者设置共享内存属性的地址

          2. shmctl(shmid, IPC_RMID, NULL);

            1. 删除共享内存

        9.  共享内存注意事项:

          1. 每块共享内存有大小限制

            1. ipcs -l

            2. cat /proc/sys/kernel/shmmax

          2. 共享内存删除的时间点

            1. shmctl(shmid, IPC_RMID, NULL); // 添加删除标记

            2. nattach变成0时真正删除

    3. 消息队列

      1. 消息队列是System V IPC对象的一种

      2. 消息队列由消息队列ID来唯一标识

      3. 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等

      4. 消息队列可以按照类型来发送/接收消息

    4. 消息队列结构:

    5. 消息队列使用步骤:

      1.  发送端:

        1. 申请key

        2. 打开/创建消息队列msgget

        3. 向消息队列发送消息msgsnd

      2. 接收端:

        1. 打开/创建消息队列 msgget

        2. 从消息队列接收消息msgrcv

        3. 控制(删除)消息队列 msgctl

    6. 消息队列创建/打开-msgget

      1. #include<sys/ipc.h>

      2. #include<sys/msg.h>

      3. int msgget(key_t key, int msgflg);

      4. 成功时返回消息队列的id,失败时返回EOF

      5. key和消息队列关联的key IPC_PRIVATE 或ftok

      6. msgflg 标志位 IPC_CREAT|0666

      7. 发送消息

        1. #include <sys/ipc.h>

        2. #include <sys/msg.h>

        3. int msgsnd(int msgid, const void *msgp, size_t size,int msgflg);

        4. 成功时返回0,失败时返回-1

        5. msgid消息队列id

        6. msgp消息缓冲区地址

        7. size消息正文长度

        8. msgflg标志位0或IPC_NOWAIT

        9. msgflg:

          1. 0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列

          2. IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回

        10. 消息格式:

          1. typedef struct{long msg_type;char buf[128];}msgT;

          2. 注意:

            1. 消息结构必须有long类型的msg_type字段,表示消息的类型。

            2. 消息长度不包括首类型long

      8. 消息的接收:

        1. #include <sys/ipc.h>

        2. #include <sys/msg.h>

        3. int msgrcv(int msgid, void *msgp, size_t size, long msgtype,int msgflg);

        4. 成功时返回收到的消息长度,失败时返回-1

        5. msgid消息队列id

        6. msgp消息缓冲区地址

        7. size指定接收的消息长度

        8. msgtype指定接收的消息类型

        9. msgflg标志位

        10. msgtype:

          1. msgtype=0:收到的第一条消息,任意类型。

          2. msgtype>0:收到的第一条msg_type类型的消息。

          3. msgtype<0:接收类型等于或者小于msgtype绝对值的第一个消息。

        11. 例子:如果msgtype=-4,只接受类型是1、2、3、4的消息

        12. msgflg:

          1. 0:阻塞式接收消息

          2. IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG

          3. MSG_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息

    7. 消息队列的控制

      1. #include <sys/ipc.h>

      2. #include <sys/msg.h>

      3. int msgctl(int msgid, int cmd, struct msqid_ds *buf);

      4. 成功时返回0,失败时返回-1

      5. msgid消息队列id

      6. cmd要执行的操作IPC_STAT / IPC_SET / IPC_RMID(删除)

      7. buf存放消息队列属性的地址

    8. 消息队列和信号灯

      1. 信号量/灯(semaphore)

        1. 信号量代表某一类资源,其值表示系统中该资源的数量

        2. 信号量是一个受保护的变量,只能通过三种操作来访问

          1. 初始化

          2. P操作(申请资源)

          3. V操作(释放资源)

        3. 概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的PV操作概念:生产者和消费者场景

        4. P/V操作

      2. 三种信号灯:

        1. Posix有名信号灯

        2. Posix无名信号灯(linux只支持线程同步)

        3. System V 信号灯

      3. Posix有名信号灯和无名信号灯使用:

        1. 有名信号灯打开:

          • sem_t *sem_open(const char *name, int oflag);

            sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

            参数:

            • name:name是给信号灯起的名字

            • oflag:打开方式,常用O_CREAT

            • mode:文件权限。常用0666

              4.value:信号量值。二元信号灯值为1,普通表示资源数目

        2. 信号灯文件位置:/dev/shm

        3. 有名信号灯关闭
          • int sem_close(sem_t *sem);
        4. 有名信号灯删除
          1. int sem_unlink(const char* name);

        5. 无名信号灯初始化

          1.  int sem_init(sem_t *sem, int shared, unsigned int value);

          2. 参数:

            1. sem:需要初始化的信号灯变量

            2. shared:shared指定为0,表示信号量只能由初始化这个信号量的进程使用,不能在进程间使用,linux不支持进程同步

            3. value:信号量的值

        6. 无名信号灯销毁

          1. int sem_destroy(sem_t *sem);

        7. 信号灯P操作

          1. int sem_wait(sem_t *sem);

          2. 获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取

        8. 信号灯V操作

          1. int sem_post(sem_t *sem);

          2. 释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem伤的线程从sem_wait函数中返回

          3. 注意:编译posix信号灯需要加pthread动态库

        9. System V信号灯使用:

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

          2. 功能:创建/打开信号灯

          3. 参数:key:ftok产生的key值(和信号灯关联的key值)

            1. nsems:信号灯集中包含的信号灯数据

            2. semflg:信号灯集的访问权限,通常为IPC_CREAT|0666

          4. 返回值:成功:信号灯集ID,失败:-1

          5. int semop(int semid,struct sembuf *opsptr,size_t nops);

            1. 功能:对信号灯集和中的信号量进行P-V操作

            2. 参数:

              1. semid:信号灯集ID

              2. struct sembuf{

                1. short sem_num;//要操作的信号灯的编号

                2. short sem_op;//1:释放资源,V操作 -1:分配资源,P操作

                3. short sem_flg;//0(阻塞),IPC_NOWAIT,SEM_UNDO

              3. };//对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构体数组

              4. nops:要操作的信号灯的个数,1个

              5. 返回值:成功0,失败-1

          6. int semctl(int semid, int semnum, int cmd../*union semun arg*/);

            1. 功能:信号灯集合的控制(初始化/删除)

            2. 参数:

              1. semid:信号灯集ID

              2. semnum:要操作的集合中的信号灯编号

              3. cmd:

                1. GETVAL:获取信号灯的值,返回的是获得值

                2. SETVAL:设置信号灯的值,需要用到第四个参数:共用体

                3. IPC_RMID:从系统中删除信号灯集合

              4. 返回值:成功0,失败-1 

  5. 套接字socket

       

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值