为了帮助同学们完成痛苦的实验课程设计,本作者将其作出的实验结果及代码贴至CSDN中,供同学们学习参考。如有不足或描述不完善之处,敬请各位指出,欢迎各位的斧正!
装有Linux系统的计算机。
Linux继承了Unix v的进程间通信机制,即消息队列、信号量和共享主存。通常把消息、信号量和共享主存统称为system v ipc对象或ipc资源。系统在进程请求ipc对象时在内核动态创建一个ipc数据结构并初始化,该结构定义了对该ipc对象访问的许可权, 每个对象都具有同样类型的接口-函数,这组函数为应用程序提供3种服务:
通过信号量实现与其他进程的同步。
通过消息队列以异步方式为通信频繁但数据量少的进程间通信提供服务。
通过共享主存,为大数据量的进程间通信提供服务。
struct ipc_ids{
int size; /*entries数组的大小*/
int in_use; /*entries数组已使用的元素个数*/
int max_id;
unsigned short seq;
unsigned short seq_max;
struct semaphore sem; /*控制对ipc_ids结构的访问*/
spinlock_t ary; /*自旋锁控制对数组entries的访问*/
struct ipc_id* entries;
};
struct ipc_id{ struct ipc_perm *p;};
每个ipc对象都有一个ipc_perm数据结构,用于描述其属性。
struct ipc_perm
{
__key_t __key; /* ipc键*/
__uid_t uid; /* Owner's user ID. */
__gid_t gid; /* Owner's group ID. */
__uid_t cuid; /* Creator's user ID. */
__gid_t cgid; /* Creator's group ID. */
unsigned short int mode;/* Read/write permission. */
unsigned short int __seq;/* Sequence number. */
};
每一个ipc对象都有一个32位的ipc键和一个ipc标识符,ipc标识符由内核分配给ipc对象,在系统内部惟一,IPC机制提供了相应的编程接口根据IPC键值获取标识符。对于一个IPC对象,在打开时返回一个标识符,而关闭后再次打开同一个IPC对象时,该标识符将顺序加1,而键是ipc对象的外部表示,可由程序员选择。不同的进程直接使用key去创建IPC对象容易引起混淆,并且不同的应用之间可能会因为使用同一个key而产生冲突。为此,Linux系统提供了如下机制产生惟一的关键字。
1)创建IPC对象时,指定关键字为IPC_PRIVATE。通过该参数创建的IPC对象的关键字值是0,所以无法在其他进程中通过关键字对该对象进行访问,只能通过返回的标识符进行访问。
2)调用函数ftok()产生一个惟一的关键字值。通过IPC进行通信的进程,只需要按照相同的参数调用ftok即可产生惟一的参数。通过该参数可有效解决关键字的产生及惟一性问题。
1.2. Linux提供的ipc函数
(1)ipc对象的创建函数
semget():获得信号量的ipc标识符
msgget():获得消息队列的ipc标识符
shmget():获得共享主存的ipc标识符
(2)ipc资源控制函数
创建ipc对象后,用户可以通过下面的库函数对ipc对象进行控制
semctl():对信号量资源进行控制
msgctl():对消息队列进行控制
shmctl():对共享主存进行控制
(3)资源操作函数
semop():用于对信号量资源进行操作,获得或释放一个ipc信号量
msgsnd()及msgrcv():发送和接收一个ipc消息
shmat()及shmdt():分别将一个ipc共享主存区附加到进程的虚拟地址空间,以及把共享主存区从进程的虚拟地址空间剥离出去
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* 队列上第一条消息,即链表头*/
struct msg *msg_last; /* 队列中的最后一条消息,即链表尾 */
time_t msg_stime; /* 发送给队列的最后一条消息的时间 */
time_t msg_rtime; /* 从消息队列接收到的最后一条消息的时间 */
time_t msg_ctime; /* 最后修改队列的时间*/
ushort msg_cbytes; /*队列上所有消息总的字节数 */
ushort msg_qnum; /*在当前队列上消息的个数 */
ushort msg_qbytes; /* 队列最大的字节数 */
ushort msg_lspid; /* 发送最后一条消息的进程的pid */
ushort msg_lrpid; /* 接收最后一条消息的进程的pid */
};
2.2、消息结构(msg)
内核把每一条消息存储在以msg结构为框架的队列中
struct msg {
struct msg *msg_next; /* 队列上的下一条消息 */
long msg_type; /*消息类型*/
char *msg_spot; /* 消息正文的地址 */
short msg_ts; /* 消息正文的大小 */
};
2.3、消息缓冲区(msgbuf)
struct msgbuf {
long mtype; /* 消息的类型,必须为正数 */
char mtext[1]; /* 消息正文 */
};
对发送消息,先预设一个msgbuf缓冲区并写入消息类型何内容,调用相应的发送函数。对读取消息,先分配一个msgbuf缓冲区。然后把消息读入该缓冲区
2.4、消息队列基本操作
(1)相应头文件
#include
#include
#include
(2)打开或创建消息队列
为了创建一个新的消息队列,或存取一个已经存在的队列,要使用msgget()系统调用
int msgget(key_t kye,int flag);
函数key是创建/打开队列的键值,直接用常量指定或由ftok()函数产生,flag参数指定创建/打开方式。
可以是ipc_create、ipc_excl、ipc_nowait或三者的或结果。
(3)发送消息
int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz,int msgflg );
第一个参数是队列标识符,由msgget()调用返回。第二个参数msgp是一个指针,指向我们重新声明和装载的消息缓冲区。msgsz参数包含了消息以字节为单位的长度,其中包括了消息类型的4个字节。msgflg参数可以设置成0(忽略),或者:
IPC_NOWAIT :如果消息队列满,消息不写到队列中,并且控制权返回给调用进程(继续执行)。如果不指定
IPC_NOWAIT,调用进程将挂起(阻塞)直到消息被写到队列中。
(4)读取消息
int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz,long mtype, int msgflg );
第一个参数用来指定要检索的队列(必须由msgget()调用返回),第二个参数(msgp)是存放检索到消息的缓冲区的地址,第三个参数(msgsz)是消息缓冲区的大小,包括消息类型的长度(4字节),第四个参数(mtype)指定了消息的类型,如果传递给mytype参数的值为0,就可以不管类型,只返回队列中最早的消息。
如果传递给参数msgflg的值为IPC_NOWAIT,并且没有可取的消息,那么给调用进程返回ENOMSG错误消息,否则,调用进程阻塞,直到一条消息到达队列并且满足msgrcv()的参数。
(5)消息队列属性操作
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
msgqid是打开的消息队列id,buf是用户缓冲区,供用户存放控制参数何查询结果,cmd是规定的命令:
IPC_STAT 读取消息队列的数据结构msqid_ds,并将其存储在b u f指定的地址中。
IPC_SET 设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。
IPC_RMID 从系统内核中移走消息队列。
(6)消息队列的应用
见试验内容1
struct sem{
int semval; /信号量的当前值/
int sempid; /在信号量上最后一次操作的进程识别号/
};
3.2、信号量集合数据结构
struct semid_ds {
struct ipc_perm sem_perm; /*IPC权限 */
long sem_otime; /* 最后一次对信号量操作(semop)的时间 */
long sem_ctime; /* 对这个结构最后一次修改的时间 */
struct sem /*sem_base; /* 在信号量数组中指向第一个信号量的指针 */
struct sem_queue *sem_pending; /* 待处理的挂起操作*/
struct sem_queue **sem_pending_last; / * 最后一个挂起操作 */
struct sem_undo *undo; /* 在这个数组上的undo 请求 */
ushort sem_nsems; /* 在信号量数组上的信号量号 */
};
3.3、信号量集中的队列结构
struct sem_queue {
struct sem_queue * next; /* 队列中下一个节点 */
struct sem_queue ** prev; /* 队列中前一个节点, *(q->prev) == q */
struct wait_queue * sleeper; /* 正在睡眠的进程 */
struct sem_undo * undo; /* undo 结构*/
int pid; /* 请求进程的进程识别号 */
int status; /* 操作的完成状态 */
struct semid_ds * sma; /*有操作的信号量集合数组 */
struct sembuf * sops; /* 挂起操作的数组 */
int nsops; /* 操作的个数 */
};
3.4、信号量基本操作
(1)头文件
#include
#include
#include
(2)打开或创建信号量
使用segget()系统调用创建一个新的信号量集合,或者存取一个已存在的集合。
int semget ( key_t key, int nsems, int semflg );
参数key和semflg取值与msgget()函数对应参数相同,nsems指定要创建或打开的信号量集合中包含的信号量数目。
(3)信号量值操作
int semop ( int semid, struct sembuf *sops, unsigned nsops);
参数sops是一个指针,它指向在集合上执行操作的数组,数组类型为sembuf,而参数nsops是在那个数组上操作的个数。
struct sembuf {
ushort sem_num; /* 在数组中信号量的索引值 */
short sem_op; /* 信号量操作值(正数、负数或0) */
short sem_flg; /* 操作标志,为IPC_NOWAIT或SEM_UNDO*/
};
如果sem_op为负数,那么就从信号量的值中减去sem_op的绝对值,这意味着进程要获取资源,这些资源是由信号量控制或监控来存取的。如果没有指定IPC_NOWAIT,那么调用进程睡眠到请求的资源数得到满足(其它的进程可能释放一些资源),如果sem_op是正数,把它的值加到信号量,这意味着把资源归还给应用程序的集合。
Linux 按如下的规则判断是否所有的操作都可以成功:操作值和信号量的当前值相加大于 0,或操作值和当前值均为 0,则操作成功。
(4)信号量属性操作
int semctl ( int semid, int semnum, int cmd, union semun arg );
semnum是将要操作的信号量个数,cmd参数表示在集合上执行的命令,arg参数的类型为semun
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort *array; /* array for GETALL & SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
void *__pad;
};
cmd命令及解释
命令
解 释
IPC_STAT
从信号量集合上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中
IPC_SET
设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值
IPC_RMID
从内核中删除信号量集合
GETALL
从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中
GETNCNT
返回当前等待资源的进程个数
GETPID
返回最后一个执行系统调用semop()进程的PID
GETVAL
返回信号量集合内单个信号量的值
GETZCNT
返回当前等待100%资源利用的进程个数
SETALL
与GETALL正好相反
SETVAL
用联合体中val成员的值设置信号量集合中单个信号量的值
3.5、信号量应用
见试验内容2
4、共享主存
由于进程的虚拟地址可以映射到任意一处物理地址,因此两个进程的虚拟地址映射到相同的物理地址上,则这两个进程就可以利用该物理地址单元进行通信,system v共享主存将需要共享的主存放在ipc共享主存区,所有需要访问该共享区的进程都要把该共享区映射到本进程的虚拟地址空间。由于多个进程共享同一块主存区,对共享主存的访问必然要使用到某种同步机制。
共享主存的基本步骤:
(1)对线程或进程使用shmget()分配主存区;
(2)使用shmat()连接一个或多个进程或线程到共享主存区中;
(3)使用shmdt()从共享区中分离;
(4)使用shmctl()解除分配空间。
4.1、基本操作
(1)头文件
#include
#include
(2)创建或获得一个共享主存区
int shmget(key_t key, size_t size, int shmflg) ;
size: 要建立共享内存的长度(打开已有共享内存时置 0) ,参数key与shmflg同msgget()函数
(3)连接共享主存区到进程虚拟空间
int *shmat(int shmid, const void *shmaddr, int shmflg) ;
shmaddr:共享内存的起始地址 ,shmflag:本进程对该内存的操作模式。
(4)从指定进程虚拟空间断开共享主存区
int shmdt(const v oid *shmaddr) ;
(5共享主存区属性控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
buf:保存内存模式状态和访问权限的数据结构,通常为 0。cmd:允许的操作,包括以下几种类型:
IPC_STAT,IPC_SET,IPC_RMID含义和消息队列属性控制函数对应一样
4.2、共享主存区应用
见试验内容3
#include
#include
#include
#include
#include
void msg_stat(int,struct msqid_ds);
main()
{
int gflags,sflags,rflags;
key_t key;
int msgid;
int reval;
struct msgsbuf{
int mtype;
char mtext[1];
}msg_sbuf;
struct msgmbuf{
int mtype;
char mtext[10];
}msg_rbuf;
struct msqid_ds msg_ginfo,msg_sinfo;
char *msgpath="/home/msgqueue";
key=ftok(msgpath,'a');
gflags=IPC_CREAT|IPC_EXCL;
msgid=msgget(key,gflags|00666);
if(msgid==-1){
printf("msg create error\n");
return;
}
msg_stat(msgid,msg_ginfo);
sflags=IPC_NOWAIT;
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a';
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
if(reval==-1){
printf("message send error\n");
}
msg_stat(msgid,msg_ginfo);
rflags=IPC_NOWAIT|MSG_NOERROR;
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
if(reval==-1){
printf("read msg error\n");
}
else
printf("read from msg queue %d bytes\n",reval);
msg_stat(msgid,msg_ginfo);
msg_sinfo.msg_perm.uid=8;
msg_sinfo.msg_perm.gid=8;
msg_sinfo.msg_qbytes=16388;
reval=msgctl(msgid,IPC_SET,&msg_sinfo);
if(reval==-1){
printf("msg set info error\n");
return;
}
msg_stat(msgid,msg_ginfo);
reval=msgctl(msgid,IPC_RMID,NULL);
if(reval==-1){
printf("unlink msg queue error\n");
return;
}
}
void msg_stat(int msgid,struct msqid_ds msg_info){
int reval;
sleep(1);
reval=msgctl(msgid,IPC_STAT,&msg_info);
if(reval==-1){
printf("get msg info error\n");
return;
}
printf("\n");
printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);
printf("number of messages in queue is %d\n",msg_info.msg_qnum);
printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);
printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
printf("last msgsnd time is%s",ctime(&(msg_info.msg_stime)));
printf("last msgrcv time is%s",ctime(&(msg_info.msg_rtime)));
printf("last change time is%s",ctime(&(msg_info.msg_ctime)));
printf("msg uid is%d\n",msg_info.msg_perm.uid);
printf("msg gid is%d\n",msg_info.msg_perm.gid);
}
程序运行结果:
current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 65536
pid of last msgsnd is 0
pid of last msgrcv is 0
Segmentation fault (core dumped)
#include
#include
#include
#define SEM_PATH "/home/hx/my_sem"
#define max_tries 3
int semid;
int main()
{
int flag1,flag2,key,i,init_ok,tmperrno;
struct semid_ds sem_info;
struct seminfo sem_info2;
union semun arg; //union semun: 请参考附录2
struct sembuf askfor_res, free_res;
flag1=IPC_CREAT|IPC_EXCL|00666;
flag2=IPC_CREAT|00666;
key=ftok(SEM_PATH,'a');
//error handling for ftok here;
init_ok=0;
semid=semget(key,1,flag1);//create a semaphore set that only includes one semphore.
if(semid<0)
{
tmperrno=errno;
perror("semget");
if(tmperrno==EEXIST)
//errno is undefined after a successful library call( including perror call) so it is saved //in tmperrno.
{
semid=semget(key,1,flag2);
//flag2 只包含了IPC_CREAT标志, 参数nsems(这里为1)必须与原来的信号灯数目一致
arg.buf=&sem_info;
for(i=0; i<max_tries; i++)
{
if(semctl(semid, 0, IPC_STAT, arg)==-1)
{ perror("semctl error"); i=max_tries;}
else
{
if(arg.buf->sem_otime!=0){ i=max_tries; init_ok=1;}
else sleep(1);
}
}
if(!init_ok)
// do some initializing, here we assume that the first process that creates the sem will
// finish initialize the sem and run semop in max_tries*1 seconds. else it will not run
// semop any more.
{
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error");
}
}
else
{perror("semget error, process exit");
exit(1);
}
}
else //semid>=0; do some initializing
{
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1)
perror("semctl setval error");
}
//get some information about the semaphore and the limit of semaphore in redhat8.0
arg.buf=&sem_info;
if(semctl(semid, 0, IPC_STAT, arg)==-1)
perror("semctl IPC STAT");
printf("owner's uid is %d\n", arg.buf->sem_perm.uid);
printf("owner's gid is %d\n", arg.buf->sem_perm.gid);
printf("creater's uid is %d\n", arg.buf->sem_perm.cuid);
printf("creater's gid is %d\n", arg.buf->sem_perm.cgid);
arg.__buf=&sem_info2;
if(semctl(semid,0,IPC_INFO,arg)==-1)
perror("semctl IPC_INFO");
printf("the number of entries in semaphore map is %d \n", arg.__buf->semmap);
printf("max number of semaphore identifiers is %d \n", arg.__buf->semmni);
printf("mas number of semaphores in system is %d \n", arg.__buf->semmns);
printf("the number of undo structures system wide is %d \n", arg.__buf->semmnu);
printf("max number of semaphores per semid is %d \n", arg.__buf->semmsl);
printf("max number of ops per semop call is %d \n", arg.__buf->semopm);
printf("max number of undo entries per process is %d \n", arg.__buf->semume);
printf("the sizeof of struct sem_undo is %d \n", arg.__buf->semusz);
printf("the maximum semaphore value is %d \n", arg.__buf->semvmx);
//now ask for available resource:
askfor_res.sem_num=0;
askfor_res.sem_op=-1;
askfor_res.sem_flg=SEM_UNDO;
if(semop(semid,&askfor_res,1)==-1)//ask for resource
perror("semop error");
sleep(3); //do some handling on the sharing resource here, just sleep on it 3 seconds
printf("now free the resource\n");
//now free resource
free_res.sem_num=0;
free_res.sem_op=1;
free_res.sem_flg=SEM_UNDO;
if(semop(semid,&free_res,1)==-1)//free the resource.
if(errno==EIDRM)
printf("the semaphore set was removed\n");
//you can comment out the codes below to compile a different version:
if(semctl(semid, 0, IPC_RMID)==-1)
perror("semctl IPC_RMID");
else printf("remove sem ok\n");
}
程序的运行结果(操作系统redhat8.0):
owner’s uid is 0
owner’s gid is 0
creater’s uid is 0
creater’s gid is 0
the number of entries in semaphore map is 32000
max number of semaphore identifiers is 128
mas number of semaphores in system is 32000
the number of undo structures system wide is 32000
max number of semaphores per semid is 250
max number of ops per semop call is 32
max number of undo entries per process is 32
the sizeof of struct sem_undo is 20
the maximum semaphore value is 32767
now free the resource
remove sem ok
Summary:信号灯与其它进程间通信方式有所不同,它主要用于进程间同步。通常所说的系统V信号灯实际上是一个信号灯的集合,可用于多种共享资源的进程间同步。每个信号灯都有一个值,可以用来表示当前该信号灯代表的共享资源可用(available)数量,如果一个进程要申请共享资源,那么就从信号灯值中减去要申请的数目,如果当前没有足够的可用资源,进程可以睡眠等待,也可以立即返回。当进程要申请多种共享资源时,Linux可以保证操作的原子性,即要么申请到所有的共享资源,要么放弃所有资源,这样能够保证多个进程不会造成互锁。Linux对信号灯有各种各样的限制,程序中给出了输出结果。另外,如果读者想对信号灯作进一步的理解,建议阅读sem.h源代码,该文件不长,但给出了信号灯相关的重要数据结构。
/***shmwritetest.c**/
#include
#include
#include
#include
typedef struct{
char name[4];
int age;
} people;
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp;
people *p_map;
char* name = "/home";
key = ftok(name,0);
if(key==-1)
perror("ftok error");
shm_id=shmget(key,4096,IPC_CREAT);
if(shm_id==-1)
{
perror("shmget error");
return;
}
p_map=(people*)shmat(shm_id,NULL,0);
temp='a';
for(i = 0;i<10;i++)
{
temp+=1;
memcpy((*(p_map+i)).name,&temp,1);
(*(p_map+i)).age=20+i;
}
if(shmdt(p_map)==-1)
perror(" detach error ");
}
/****shmreadtest.c*****/
#include
#include
#include
#include
typedef struct{
char name[4];
int age;
} people;
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people *p_map;
char* name = "/home";
key = ftok(name,0);
if(key == -1)
perror("ftok error");
shm_id = shmget(key,4096,IPC_CREAT);
if(shm_id == -1)
{
perror("shmget error");
return;
}
p_map = (people*)shmat(shm_id,NULL,0);
for(i = 0;i<10;i++)
{
printf( "name:%s\n",(*(p_map+i)).name );
printf( "age %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
perror(" detach error ");
}
shmwritetest.c创建一个系统V共享内存区,并在其中写入格式化数据;shmreadtest.c访问同一个系统V共享内存区,读出其中的格式化数据。分别把两个程序编译为shmwritetest及shmreadtest,先后执行./shmwritetest及./shmreadtest 则./shmreadtest输出结果如下:
name: b age 20; name: c age 21; name: d age 22; name: e age 23; name: f age 24;
name: g age 25; name: h age 26; name: I age 27; name: j age 28; name: k age 29;
通过对试验结果分析,对比系统V与mmap()映射普通文件实现共享内存通信,可以得出如下结论:
#include
#include
#include
#include
#include
void msg_stat(int,struct msqid_ds);
main()
{
int gflags,sflags,rflags;
key_t key;
int msgid;
int reval;
struct msgsbuf{
int mtype;
char mtext[1];
}msg_sbuf;
struct msgmbuf{
int mtype;
char mtext[10];
}msg_rbuf;
struct msqid_ds msg_ginfo,msg_sinfo;
char *msgpath="/home/msgqueue";
key=ftok(msgpath,'a');
gflags=IPC_CREAT|IPC_EXCL;
msgid=msgget(key,gflags|00666);
if(msgid==-1){
printf("msg create error\n");
return;
}
msg_stat(msgid,msg_ginfo);
sflags=IPC_NOWAIT;
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a';
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
if(reval==-1){
printf("message send error\n");
}
msg_stat(msgid,msg_ginfo);
rflags=IPC_NOWAIT|MSG_NOERROR;
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
if(reval==-1){
printf("read msg error\n");
}
else
printf("read from msg queue %d bytes\n",reval);
msg_stat(msgid,msg_ginfo);
msg_sinfo.msg_perm.uid=8;
msg_sinfo.msg_perm.gid=8;
msg_sinfo.msg_qbytes=16388;
reval=msgctl(msgid,IPC_SET,&msg_sinfo);
if(reval==-1){
printf("msg set info error\n");
return;
}
msg_stat(msgid,msg_ginfo);
reval=msgctl(msgid,IPC_RMID,NULL);
if(reval==-1){
printf("unlink msg queue error\n");
return;
}
}
void msg_stat(int msgid,struct msqid_ds msg_info){
int reval;
sleep(1);
reval=msgctl(msgid,IPC_STAT,&msg_info);
if(reval==-1){
printf("get msg info error\n");
return;
}
printf("\n");
printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);
printf("number of messages in queue is %d\n",msg_info.msg_qnum);
printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);
printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
printf("last msgsnd time is%s",ctime(&(msg_info.msg_stime)));
printf("last msgrcv time is%s",ctime(&(msg_info.msg_rtime)));
printf("last change time is%s",ctime(&(msg_info.msg_ctime)));
printf("msg uid is%d\n",msg_info.msg_perm.uid);
printf("msg gid is%d\n",msg_info.msg_perm.gid);
}
#include
#include
#include
#define SEM_PATH "/home/hx/my_sem"
#define max_tries 3
int semid;
int main()
{
int flag1,flag2,key,i,init_ok,tmperrno;
struct semid_ds sem_info;
struct seminfo sem_info2;
union semun arg; //union semun: 请参考附录2
struct sembuf askfor_res, free_res;
flag1=IPC_CREAT|IPC_EXCL|00666;
flag2=IPC_CREAT|00666;
key=ftok(SEM_PATH,'a');
//error handling for ftok here;
init_ok=0;
semid=semget(key,1,flag1);//create a semaphore set that only includes one semphore.
if(semid<0)
{
tmperrno=errno;
perror("semget");
if(tmperrno==EEXIST)
//errno is undefined after a successful library call( including perror call) so it is saved //in tmperrno.
{
semid=semget(key,1,flag2);
//flag2 只包含了IPC_CREAT标志, 参数nsems(这里为1)必须与原来的信号灯数目一致
arg.buf=&sem_info;
for(i=0; i<max_tries; i++)
{
if(semctl(semid, 0, IPC_STAT, arg)==-1)
{ perror("semctl error"); i=max_tries;}
else
{
if(arg.buf->sem_otime!=0){ i=max_tries; init_ok=1;}
else sleep(1);
}
}
if(!init_ok)
// do some initializing, here we assume that the first process that creates the sem will
// finish initialize the sem and run semop in max_tries*1 seconds. else it will not run
// semop any more.
{
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error");
}
}
else
{perror("semget error, process exit");
exit(1);
}
}
else //semid>=0; do some initializing
{
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1)
perror("semctl setval error");
}
//get some information about the semaphore and the limit of semaphore in redhat8.0
arg.buf=&sem_info;
if(semctl(semid, 0, IPC_STAT, arg)==-1)
perror("semctl IPC STAT");
printf("owner's uid is %d\n", arg.buf->sem_perm.uid);
printf("owner's gid is %d\n", arg.buf->sem_perm.gid);
printf("creater's uid is %d\n", arg.buf->sem_perm.cuid);
printf("creater's gid is %d\n", arg.buf->sem_perm.cgid);
arg.__buf=&sem_info2;
if(semctl(semid,0,IPC_INFO,arg)==-1)
perror("semctl IPC_INFO");
printf("the number of entries in semaphore map is %d \n", arg.__buf->semmap);
printf("max number of semaphore identifiers is %d \n", arg.__buf->semmni);
printf("mas number of semaphores in system is %d \n", arg.__buf->semmns);
printf("the number of undo structures system wide is %d \n", arg.__buf->semmnu);
printf("max number of semaphores per semid is %d \n", arg.__buf->semmsl);
printf("max number of ops per semop call is %d \n", arg.__buf->semopm);
printf("max number of undo entries per process is %d \n", arg.__buf->semume);
printf("the sizeof of struct sem_undo is %d \n", arg.__buf->semusz);
printf("the maximum semaphore value is %d \n", arg.__buf->semvmx);
//now ask for available resource:
askfor_res.sem_num=0;
askfor_res.sem_op=-1;
askfor_res.sem_flg=SEM_UNDO;
if(semop(semid,&askfor_res,1)==-1)//ask for resource
perror("semop error");
sleep(3); //do some handling on the sharing resource here, just sleep on it 3 seconds
printf("now free the resource\n");
//now free resource
free_res.sem_num=0;
free_res.sem_op=1;
free_res.sem_flg=SEM_UNDO;
if(semop(semid,&free_res,1)==-1)//free the resource.
if(errno==EIDRM)
printf("the semaphore set was removed\n");
//you can comment out the codes below to compile a different version:
if(semctl(semid, 0, IPC_RMID)==-1)
perror("semctl IPC_RMID");
else printf("remove sem ok\n");
}
/***shmwritetest.c**/
#include
#include
#include
#include
typedef struct{
char name[4];
int age;
} people;
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp;
people *p_map;
char* name = "/home";
key = ftok(name,0);
if(key==-1)
perror("ftok error");
shm_id=shmget(key,4096,IPC_CREAT);
if(shm_id==-1)
{
perror("shmget error");
return;
}
p_map=(people*)shmat(shm_id,NULL,0);
temp='a';
for(i = 0;i<10;i++)
{
temp+=1;
memcpy((*(p_map+i)).name,&temp,1);
(*(p_map+i)).age=20+i;
}
if(shmdt(p_map)==-1)
perror(" detach error ");
}
/****shmreadtest.c*****/
#include
#include
#include
#include
typedef struct{
char name[4];
int age;
} people;
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people *p_map;
char* name = "/home";
key = ftok(name,0);
if(key == -1)
perror("ftok error");
shm_id = shmget(key,4096,IPC_CREAT);
if(shm_id == -1)
{
perror("shmget error");
return;
}
p_map = (people*)shmat(shm_id,NULL,0);
for(i = 0;i<10;i++)
{
printf( "name:%s\n",(*(p_map+i)).name );
printf( "age %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
perror(" detach error ");
}