IPC_oracle update nowaitT 宏值是多少

信号量和共享内存的配合使用原理解析
信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对临界资源访问的同步。
信号量的值大于或等于0时表示可供并发进程使用的资源实体数;小于0时代表正在等待使用临界资源的进程数
1、信号集的创建或打开
int semget(key_t key, int sems, int sem_flags);
key 是由ftok()的到的键值。 nsems指明要创建的信号集包含的信号个数,改参数后面还会提到。semflg为操作标志
IPC_CREATE:调用semget()时,会将本信号集中的key值和其他信号集中的key进行对比,如果存在相同的key,说明信号集已存在,此时返回该信号集的标识符,否则新建一个信号集并返回其标识符。 IPC_EXCL:该宏和IPC_CREATE一起使用,否则没有意义。当 semflg取PC_CREATE|IPC_EXCL时,表示如果发现信号集已经存在,则返回错误,错误码
为EEXIST。
2、信号量的操作
int semop(int semid, struct sembuf *sops, size_t nsops);
semid为信号集的标识符;sops指向进行操作的结构体首地址;nsops指出将要进行操作的信号个数。semop函数调用成功返回0,失败返回-1。
struct sembuf{
short sem_//信号在信号集中的索引
short sem_//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
//一个是+1,即V(发送信号)操作。
short sem_//操作标志IPC_NOWAIT,IPC_UNDO 详细请见UNIX高级环境
sem_op & 0
信号机上sem_op的值,表示进程释放控制的资源
如果没有设置IPC_NOWAIT则调用进程进入睡眠状态,直到信号值为0;否则不会睡眠,直接返回EAGAIN
sem_op & 0
信号加上sem_op的值。若没有设置IPC_NOWAIT,则调用进程阻塞,直到资源可用;否则进程直接返回EAGAIN
信号集的控制
int semctl(int semid, int semnum, int cmd, ... /*
union semun arg
semid为信号集的标识符;semnum标识一个特定的信号;cmd指明控制操作的类型;&&&说明函数的参数时可选的
union semun
/*for SETVAL*/
struct semid_ds * /*for IPC_STAT and IPC_SET*/
unsigned short * /*for GETALL and SETALL*/
cmd参数指定下列命令中的一种
共享内存就是分配一块能被其他进程访问的内存。
共享内存区的创建
int shmget(key_t key, size_t size, int shmflg);
IPC_CREATE: 调用sheget时,将此值与其他所有共享内存区的key进行比较,如果存在相同的key,说明共享内存区已存在,此时返回该共享内存区的标识符,否则新建一个共享内存区并返回其标识符。
IPC_EXC: 该宏必须和IPC_CREATE 一起使用,否则没有意义。当shmflg取IPC_CREATE|IPC_EXCL时,表示如果发现信号集已经存在,则返回-1,错误码为EEXIST。
共享内存区的操作
在使用共享内存区前,必须通过shmat函数将其附加到进程的地址空间。进程与共享内存就建立了连接。
void* shmat(int shmid, const void* shmaddr, int shmflag);
shmid为shmget函数的返回值;参数shmflg为存取权限标志;参数shmaddr为共享内存的附加点,其不同取值说明如下:
进程结束使用共享内存后,要通过shmdt断开与共享内存区的连接。
int shmdt(const void* shmaddr);
参数shmaddr为shmat函数的返回值。调用成功返回0,否则返回-1。
共享内存区的控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid为共享内存区的标识符;buf为指向shmid_ds结构体的指针;cmd为操作标志位
- IPC_RMID : 从系统中删除由shmid标识的共享内存区。
- IPC_SET : 设置共享内存区的shmid_ds结构。
- IPC_STAT : 读取共享内存区的shmid_ds结构,并将其存储到buf指向的地址中。
union semun
struct semid_ds *
unsigned short *
struct seminfo *__
key_t Ftok(const char *pathname, int proj_id)
key_t key = ftok(pathname, proj_id);
if(key == -1)
perror(&ftok.&);
int Semget(key_t key, int nsems, int semflg)
int id = semget(key, nsems, semflg);
if(id == -1)
perror(&semget.&);
int Shmget(key_t key, size_t size, int shmflg)
int id = shmget(key, size, shmflg);
if(id == -1)
perror(&shmget.&);
void* Shmat(int shmid, const void *shmaddr, int shmflg)
void *addr = shmat(shmid, shmaddr, shmflg);
if(addr == (void*)-1)
perror(&shmat.&);
int Msgget(key_t key, int msgflg)
int id = msgget(key, msgflg);
if(id == -1)
perror(&msgget.&);
#include&ipc.h&
void cli_exit(int signo)
printf(&Client exit. . .\n&);
// ./cli . 0xff
int main(int argc, char *argv[])
act.sa_handler = cli_
key_t shm_key = Ftok(argv[1], atoi(argv[2]));
int shm_id = Shmget(shm_key, 0, 0);
char *addr = (char*)Shmat(shm_id, NULL, 0);
int sem_id = Semget(shm_key, 0, 0);
struct sembuf v = {1, 1, SEM_UNDO};
struct sembuf p = {0, -1, SEM_UNDO};
sigaction(SIGINT, &act, NULL);
semop(sem_id, &p, 1);
printf(&Ser:&%s\n&,addr);
printf(&Cli:&&);
scanf(&%s&,addr);
semop(sem_id, &v, 1);
#include&ipc.h&
int shm_id, sem_
void ser_exit(int signo)
semctl(sem_id, 0, IPC_RMID);
semctl(sem_id, 1, IPC_RMID);
shmdt(addr);
shmctl(shm_id, IPC_RMID, NULL);
printf(&Server exit . . .\n&);
// ./ser . 0xff
int main(int argc, char *argv[])
act.sa_handler = ser_
key_t shm_key = Ftok(argv[1], atoi(argv[2]));
shm_id = Shmget(shm_key, 1024, IPC_CREAT|IPC_EXCL|0755);
addr = (char*)Shmat(shm_id, NULL, 0);
sem_id = Semget(shm_key, 2, IPC_CREAT|IPC_EXCL|0755);
init.val = 0;
semctl(sem_id, 0, SETVAL, init);
semctl(sem_id, 1, SETVAL, init);
struct sembuf v = {0, 1, SEM_UNDO};
//第一个参数代表0标志位,第二个是v操作后加的值
struct sembuf p = {1, -1, SEM_UNDO};
//第三个参数分为IPC_NOWAIT和SEM_UNDO
sigaction(SIGINT, &act, NULL);
printf(&Ser:&&);
scanf(&%s&,addr);
semop(sem_id, &v, 1);
semop(sem_id, &p, 1);
printf(&Cli:&%s\n&,addr);非阻塞IO 和阻塞IO:
&&&&&&&在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:&&&&&&&基本概念:
&&&&&&&&&&&&&&阻塞IO::
&&&&&&&&&&&&&&&&&&&&&socket 的阻塞模式意味着必须要做完IO 操作(包括错误)才会
&&&&&&&&&&&&&&&&&&&& 返回。
&&&&&&&&&&&&&&非阻塞IO::
&&&&&&&&&&&&&&&&&&&& 非阻塞模式下无论操作是否完成都会立刻返回,需要通过其他方
&&&&&&&&&&&&&&&&&&&&&式来判断具体操作是否成功。
IO模式设置:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&SOCKET&&&&&&&对于一个socket 是阻塞模式还是非阻塞模式有两种方式来处理::
&&&&&&&方法1、fcntl 设置;用F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;
&&&&&&&方法2、recv,send 系列的参数。(读取,发送时,临时将sockfd或filefd设置为非阻塞)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&方法一的实现
&fcntl 函数可以将一个socket 句柄设置成非阻塞模式:&&&&&& flags = fcntl(sockfd, F_GETFL, 0);&&&&&&&&&&&&&&&&&&&&&&&//获取文件的flags值。
&&&&& fcntl(sockfd, F_SETFL, flags&|&O_NONBLOCK);&& //设置成非阻塞模式;
&&&&& flags& = fcntl(sockfd,F_GETFL,0);
&&&&&&fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK);&&&&//设置成阻塞模式;
&&&&&&设置之后每次的对于sockfd 的操作都是非阻塞的。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&方法二的实现
&&& recv, send 函数的最后有一个flag 参数可以设置成MSG_DONTWAIT
&&&&&&&&&&&&&临时将sockfd 设置为非阻塞模式,而无论原有是阻塞还是非阻塞。
&&&&recv(sockfd, buff, buff_size,MSG_DONTWAIT);&&&& //非阻塞模式的消息发送
&&&&send(scokfd, buff, buff_size, MSG_DONTWAIT);&& //非阻塞模式的消息接受
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&普通文件
&&&&&&& 对于文件的阻塞模式还是非阻塞模式::
&&&&&&&&方法1、open时,使用O_NONBLOCK;
&&&&&&&&方法2、fcntl设置,使用F_SETFL,flags|O_NONBLOCK;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&消息队列
&&&&&&&&对于消息队列消息的发送与接受::
&&&&&&&&//非阻塞&&msgsnd(sockfd,msgbuf,msgsize(不包含类型大小),IPC_NOWAIT)
&&&&&&& //阻塞&&&&&msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);
&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&读&&&&&&&&&&&&&&&&
阻塞与非阻塞读的区别:& //阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回.
读(read/recv/msgrcv):
&&&&&&&读的本质来说其实不能是读,在实际中, 具体的接收数据不是由这些调用来进行,是由于系统底层自动完成的。read 也好,recv 也好只负责把数据从底层缓冲copy 到我们指定的位置.
&&&&& &对于读来说(read, 或者recv) ::
阻塞情况下::
&&&&&& 在阻塞条件下,read/recv/msgrcv的行为::
&&&&&& 1、如果没有发现数据在网络缓冲中会一直等待,
&&&&&&&2、当发现有数据的时候会把数据读到用户指定的缓冲区,但是如果这个时候读到的数据量比较少,比参数中指定的长度要小,read 并不会一直等待下去,而是立刻返回。
&&&&&&&read 的原则::是数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待。
&&&&&&&所以一般情况下::我们读取数据都需要采用循环读的方式读取数据,因为一次read 完毕不能保证读到我们需要长度的数据,
&&&&&&&read 完一次需要判断读到的数据长度再决定是否还需要再次读取。
非阻塞情况下::
&&&&&& 在非阻塞的情况下,read 的行为::
&&&&&&&1、如果发现没有数据就直接返回,
&&&&&& 2、如果发现有数据那么也是采用有多少读多少的进行处理.
&&&&&&&&&&&& 所以::read 完一次需要判断读到的数据长度再决定是否还需要再次读取。
对于读而言::&&&阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回.&&&&&&&recv 中有一个MSG_WAITALL 的参数::
&&&&&&&recv(sockfd, buff, buff_size, MSG_WAITALL),&&&&&& 在正常情况下recv 是会等待直到读取到buff_size 长度的数据,但是这里的WAITALL 也只是尽量读全,在有中断的情况下recv 还是可能会被打断,造成没有读完指定的buff_size的长度。
&&&&&&&所以即使是采用recv + WAITALL 参数还是要考虑是否需要循环读取的问题,在实验中对于多数情况下recv (使用了MSG_WAITALL)还是可以读完buff_size,
&&&&&& 所以相应的性能会比直接read 进行循环读要好一些。
注意::&&&&& //使用MSG_WAITALL时,sockfd必须处于阻塞模式下,否则不起作用。
&&&&&&&&&&&&&& //所以MSG_WAITALL不能和MSG_NONBLOCK同时使用。
&&&&&&&要注意的是使用MSG_WAITALL的时候,sockfd 必须是处于阻塞模式下,否则WAITALL不能起作用。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&写&
阻塞与非阻塞写的区别:&&&& //写(send/write/msgsnd)::
&&&&&&&写的本质也不是进行发送操作,而是把用户态的数据copy 到系统底层去,然后再由系统进行发送操作,send,write返回成功,只表示数据已经copy 到底层缓冲,而不表示数据已经发出,更不能表示对方端口已经接收到数据.&&&&&& 对于write(或者send)而言,
阻塞情况下::&&&&&&&&&&&&&&&& //阻塞情况下,write会将数据发送完。(不过可能被中断)
&&&&&& 在阻塞的情况下,是会一直等待,直到write 完,全部的数据再返回.这点行为上与读操作有所不同。
&&&&&&&&原因::
&&&&&&&&&&&&& 读,究其原因主要是读数据的时候我们并不知道对端到底有没有数据,数据是在什么时候结束发送的,如果一直等待就可能会造成死循环,所以并没有去进行这方面的处理;
&&&&&&&&&&&&&&写,而对于write, 由于需要写的长度是已知的,所以可以一直再写,直到写完.不过问题是write 是可能被打断吗,造成write 一次只write 一部分数据, 所以write 的过程还是需要考虑循环write,&只不过多数情况下一次write 调用就可能成功.
非阻塞写的情况下::&&&& //
&&&&&& 非阻塞写的情况下,是采用可以写多少就写多少的策略.与读不一样的地方在于,有多少读多少是由网络发送的那一端是否有数据传输到为标准,但是对于可以写多少是由本地的网络堵塞情况为标准的,在网络阻塞严重的时候,网络层没有足够的内存来进行写操作,这时候就会出现写不成功的情况,阻塞情况下会尽可能(有可能被中断)等待到数据全部发送完毕, 对于非阻塞的情况就是一次写多少算多少,没有中断的情况下也还是会出现write 到一部分的情况.
阅读(...) 评论()【图文】Linux下的IPC_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Linux下的IPC
&&Linux课件郭玉华
大小:976.50KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢下次自动登录
现在的位置:
& 综合 & 正文
Linux进程通信之消息队列-项目实践
消息队列的基本概念:消息队列
(也叫做报文队列)是系统V版本中3种进程间机制之一。另外两种是信号灯和共享内存。这些IPC机制使用共同的授权方法。只有通过系统调用将标志符传递给核心之后,进程才能存取这些资源。这种系统IPC对象使用的控制方法和文件系统非常类似。使用对象的引用标志符作为资源表中的索引。
上面是到别的地方copy的一些蛋疼的基本概念,看一百遍都是那么回事,说穿了,想要操作一个消息队列首先得获得他的msqid,啥?你不知道msqid,看图~~~
看见msqid木有,是吧。(ipcs -q,是为了查看当前系统中的消息队列,ipcs -m 查看共享内存),里面的几个字段,如key,msqid,owner,perms used-bytes,messages都是很有用的,请听我娓娓道来。。。。
key:msqid是IPC对象的内部名,为了使多个进程能访问同一个IPC对象,所以必须提供一个外部的key,那你是不是很疑惑,“我都知道了msqid,还要key干叼”,问得好,么急,这又的从消息队里的创建开始说了,我们来看,消息队里的创建/获取消息队里的操作权限,要用到msqid=msgget(ket_t key, int flag), 看到key木有,所有的消息队列创建之前或者获取一个消息队列的操作权限都要先给一个key,所以不同的进程通过相同的key可以得到相同的消息队列(操作权限),明白了吗,亲?
那我们再来说key的创建:key_t ftok( const char * path, int id )
path:服务器和客户进程都认可的同一文件路径,
id:子序号,一般设置0-255的数
概念性的东西,咱也解释不大清楚,想多了解就去百度上面google下。
注:msgget(ket_t key, int flag)中key的值,可以直接给一个IPC_PRIVATE的宏, 但是每次创建的进程都是一个崭新的消息队列,对于需要拿来给客户服务器通信的消息队列来说,这有叼用。(水平有限,可能还真有叼用也未可而知)
有了key之后,下一步就是创建消息队列了,就如前面说到的msgget函数,flag标志其实就是权限位,如同咱创建一个文件时(open)后面的权限位。flag取值有IPC_CREAT、IPC_EXCL同时可以再或上一个具体的权限如“0600”(就是咱执行ipcs-q时看到的perm),如msgget(key,IPC_CREAT|0600),由于要做成接口时要封装msgget,所以msgget的flag这个给就行了,至于IPC_EXCl与IPC_CREAT一起使用,如果该消息队列已创建,则返回错。IPC_EXCl也只能用到也别的需求的地方这里就不扯了。
下面来说说下一步的消息的收发:
msgsnd( int msqid , struct msgbuf *msgp , size_t msgsiz , int msgflag );向消息队列送消息返回值:
失败时:-1
已打开的消息队列返回值
存放消息的结构
消息数据长度
:发送标志,有意义的标志为指明在消息队列没有足够的空间容纳要发送的消息时,是否等待
//消息类型
mtext[256];
//消息数据的首地址
msgrcv(int msqid,struct msgbuf *msgp, int msgsz,long
msgtyp, int
功能:从代表的消息队列中读取一个类型的消息,并把消息存储在指向的结构中。在成功地读取了一条消息以后,队列中的这条消息将被删除。
返回值:失败返回-1,成功返回接收到的字节数
已打开的消息队列返回值
存放消息的结构
消息数据长度
msgtyp: 要接受消息数据类型(啥,你不懂接收啥类型,好的,看下面的)
:发送标志,有意义的标志为指明在消息队列没有足够的空间容纳要发送的消息时,是否等待
==0;返回消息队列第一条消息
//消息类型
mtext[256];
//消息数据的首地址
其中的mtype即你要发送的类型,如果你填1,后面msgrcv的时候,msgtyp就的填1,具体你想怎么给,看需求
mtext[256];
就是你要发送的消息,填充大小随意但是不能超过内核限制的值,咋看?ipcs -l
------ Messages: Limits --------
max queues system wide = 1024
max size of message (bytes) = 8192//看这里,别瞎看,这个就是内核限制的最大消息数,可以改具体请百度。default max size of queue (bytes) = 16384
IPC_NOWAIT:非阻塞
当使用msgsnd函数时,
cmd:IPC_STAT 取msqid指定的队列信息(不是消息就像咱们执行ipcs -q一样)即取出它在系统中的状态。存放在buf中,buf后面说
IPC_SET 将buf中的数据传递给msqid指定的消息队列,以达到设置其属性的z作用.
IPC_RMID 删除msqid指定的消息队列,buf给NULL
struct msqid_ds {
  struct ipc_perm msg_
  struct msg *msg_ /* first message on queue */
  struct msg *msg_ /* last message in queue */
  __kernel_time_t msg_ /* last msgsnd time */
  __kernel_time_t msg_ /* last msgrcv time */
  __kernel_time_t msg_ /* last change time */
  struct wait_queue *
  struct wait_queue *
  unsigned short msg_ /* current number of bytes on queue */
  unsigned short msg_ /* number of messages in queue */
  unsigned short msg_ /* max number of bytes on queue */
  __kernel_ipc_pid_t msg_ /* pid of last msgsnd */
  __kernel_ipc_pid_t msg_ /* last receive pid */
  其中包括:
  l 一个ipc_perm的数据结构(msg_perm域),描述该消息队列的通用认证方式。
  l 一对消息指针(msg_first、msg_last),分别指向该消息队列的队头(第一个消息)和队尾(最后一个消息)(msg)。发送者将新消息加到队尾,接收者从队头读取消息。
  l 三个时间域(msg_stime、msg_rtime、msg_ctime)用于记录队列最后一次发送时间、接收时间和改动时间。
  l 两个进程(wwait、rwait)分别表示等待向消息队列中写的进程(wwait)和等待从消息队列中读的进程(rwait)。如果某进程向一个消息队列发送消息而发现该队列已满,则进程挂在wwait队列中等待。从该消息队列中读取消息的进程将从队列中删除消息,从而腾出空间,再唤醒wwait队列中等待的进程。如果某进程从一个消息队列中读消息而发现该队列已空,则进程挂在rwait队列中等待。向该消息队列中发送消息的进程将消息加入队列,再唤醒rwait队列中等待的进程。
  l 三个记数域(msg_cbytes、msg_qnum、msg_qbytes)分别表示队列中的当前字节数、队列中的消息数和队列中最大字节数;
  l 两个PID域(msg_lspid、msg_lrpid)分别表示最后一次向该消息队列中发送消息的进程和最后一次从该消息队列中接收消息的进程。
这坐半天不动 屁股也疼 腰也酸,玛德 年纪轻轻的,哎~
#ifndef __MSQ_H__
#define __MSQ_H__
#include&string&
int create_msq(int _ikey);
int send_msq(string &_strSnd, long _lType, int _iFlg, string &_strErr);
int recv_msq(string &_strRcv, long _lType, int _iFlg, string &_strErr);
int get_msq_ds(struct msqid_ds *_pMsq);
int set_msq_mode(struct msqid_ds *_pMsq, const char* _pMode);
int free_msq();
struct MsqBuf
char cData[1024];
MsqBuf():lType(long()){memset(cData, 0, 1024);}
#include"msq.h"
#include&sys/msg.h&
#include&sys/ipc.h&
#include&sys/types.h&
#include&sys/stat.h&
#include&errno.h&
MsQ::MsQ()
MsQ::~MsQ()
int MsQ::create_msq(int _iKey)
m_iMqid = msgget(_iKey, IPC_CREAT|S_IRUSR|S_IWUSR);
return m_iM
int MsQ::send_msq(string& _strSnd, long _lType, int _iFlg, string& _strErr)
char cErr[100] = {0};
mBuf.lType = _lT
strcpy(mBuf.cData, (char*)_strSnd.c_str());
if( _iFlg != 0 )
_iFlg = IPC_NOWAIT;
iRet = msgsnd(m_iMqid, &mBuf, _strSnd.length()+1, _iFlg);
if( iRet == -1 )
sprintf( cErr, "[发送消息失败:%s]", strerror(errno));
_strErr = cE
int MsQ::recv_msq(string& _strRcv, long _lType, int _iFlg, string& _strErr)
char cErr[100] = {0};
if( _iFlg != 0 )
_iFlg = IPC_NOWAIT;
iRet = msgrcv(m_iMqid, &mBuf, 1024, _lType, _iFlg);
if( iRet == -1 )
sprintf( cErr, "[接收消息失败:%s]", strerror(errno));
_strErr = cE
_strRcv = mBuf.cD
int MsQ::get_msq_ds(struct msqid_ds *_pMsq)
return msgctl(m_iMqid, IPC_STAT, _pMsq);
int MsQ::set_msq_mode(struct msqid_ds *_pMsq, const char* _pMode)
sscanf(_pMode, "%ho", &_pMsq-&msg_perm.mode);
return msgctl(m_iMqid, IPC_SET, _pMsq);
int MsQ::free_msq()
return msgctl(m_iMqid, IPC_RMID, NULL);
&&&&推荐文章:
【上篇】【下篇】Access denied |
used Cloudflare to restrict access
Please enable cookies.
What happened?
The owner of this website () has banned your access based on your browser's signature (3bc96da1a648283a-ua98).}

我要回帖

更多关于 oracle update nowait 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信