day9-消息队列和信号灯

消息队列的使用:

发送端:

1 申请Key

2打开/创建消息队列 msgget

3向消息队列发送消息 msgsnd

接收端:

1打开/创建消息队列 msgget

2从消息队列接收消息 msgrcv

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

打开/创建消息队列

 #include <sys/ipc.h>
 #include <sys/msg.h>
 int msgget(key_t key, int msgflg);

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

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

msgflg 标志位 IPC_CREAT|0666 IPC_CREAT:没有创建,有则打开。

发送消息

 #include <sys/ipc.h>
 #include <sys/msg.h>
 int msgsnd(int msgid, const void *msgp, size_t size,int msgflg);

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

msgid 消息队列id

msgp 消息缓冲区地址

size 消息正文长度

msgflg 标志位 0 或 IPC_NOWAIT

msgflg:

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

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

消息格式:

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

注意:

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

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

消息的接收:

 #include <sys/ipc.h>
 #include <sys/msg.h>
 intmsgrcv(int msgid, void *msgp, size_t size, long msgtype,int msgflg);

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

msgid 消息队列id

msgp 消息缓冲区地址

size 指定接收的消息长度

msgtype 指定接收的消息类型

msgflg 标志位

msgtype:

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

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

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

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

msgflg:

0:阻塞式接收消息

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

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

消息队列的控制

#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf);

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

msgid 消息队列id

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

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

信号量/灯

概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的

PV操作概念:

P操作(申请资源)

V操作(释放资源)

P(S) 含义如下:

if (信号量的值大于0) {

申请资源的任务继续运行;

信号量的值减一;

} else {

申请资源的任务阻塞;

}

V(S) 含义如下:

信号量的值加一;

if (有任务在等待资源) {

唤醒等待的任务,让其继续运行

}

三种信号灯:

Posix 有名信号灯

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

System V 信号灯

有名信号灯

有名信号灯打开:

sem_t *sem_open(const char *name, intoflag);

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

参数:

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

oflag:打开方式,常用O_CREAT

mode:文件权限。常用0666

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

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

有名信号灯关闭

int sem_close(sem_t *sem);

有名信号灯的删除

int sem_unlink(const char* name);

无名信号灯

无名信号灯初始化

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

参数:

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

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

Value:信号量的值

名信号灯销毁

int sem_destroy(sem_t* sem);

信号灯P操作

int sem_wait(sem_t *sem);

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

信号灯V操作

int sem_post(sem_t *sem);

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

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

System V 信号灯使用:

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

功能:创建/打开信号灯

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

       nsems:信号灯集中包含的信号灯数目

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

返回值:成功:信号灯集ID ;失败:-1

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

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

参数:semid:信号灯集ID

   struct sembuf {

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

    short sem_op; // 1 : 释放资源,V操作

// -1 : 分配资源,P操作

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

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

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

返回值:成功:0 ;失败:-1

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

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

参数:semid:信号灯集ID

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

   cmd:

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

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

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

返回值:成功 0 ;失败 -1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值