Linux IPC备忘
来源:互联网 发布:公司财务战略矩阵 编辑:程序博客网 时间:2024/05/01 19:27
大概在很久之前就一直关注的ipc问题因为一直没有怎么使用也不是很明了,实在是为了自己的懒惰而汗颜了。经典的ipc里面除了自己曾经用到过的 pthread_mutex之外,对其他的几种都不了解。自己学习的话也说了不少,可是都没有什么效果,看书似乎都看不动。
最近整理了一下几种ipc方式的使用,一些小问题,在此存档:
一.posix的msgqueue的支持问题。
要说明的是从一开始就觉得所谓的posix的兼容是很好的一个东西,而linux对posix的兼容性很好也是一直以来发展linuxer的一个重要的游 说砝码。但是在开始测试posix message queue的时候遭到了当头一棒。程序编译通过,连接出错!然后google到nptl的知识,声称posix msgqueue的支持在mm分支中发展。晕先。不甘心的同时在新下载的2.6.18里面发现了如下说明:
2.6.18的内核里面关于posix message-queue的选项说明:
CONFIG_POSIX_MQUEUE:
POSIX variant of message queues is a part of IPC. In POSIX message
queues every message has a priority which decides about succession
of receiving it by a process. If you want to compile and run
programs written e.g. for Solaris with use of its POSIX message
queues (functions mq_*) say Y here. To use this feature you will
also need mqueue library, available from
<http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
POSIX message queues are visible as a filesystem called 'mqueue'
and can be mounted somewhere if you want to do filesystem
operations on message queues.
If unsure, say Y.
Symbol: POSIX_MQUEUE [=y]
Prompt: POSIX Message Queues
Defined at init/Kconfig:118
Depends on: NET && EXPERIMENTAL
同时在2.6.16里面这个还是没有的,真是庆幸啊,要是早点开始关注这个岂不是要郁闷很久或者麻烦很久。遵照上面内核编译系统给出的信息,上网站一看原 来已经转到了:http://www.geocities.com/wronski12/posix_ipc/index.html.下载了: libmqueue-4.41.tar.gz。经典的三步之后再编译。bingle!
程序清单:posixqueue.c
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#define MSGQUEUE_NAME "/tllmsgqueue"
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
char msgQueueName[MAXMSGNAMELENGTH];
struct mq_attr msgattr;
unsigned int timeInterval;
};
void msgSendThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
mq_unlink(para->msgQueueName);
mqd_t mqid;
char buffer[MSG_LENGTH]={0};
unsigned int counter=0;
mode_t mode;
mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
mqid=mq_open(para->msgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
if(mqid == -1)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("SendThread:open msqueue failed!/n");
return;
}
for(;counter<10;counter++)
{
sprintf(buffer,"this is the #%d message",counter);
mq_send(mqid,buffer,MSG_LENGTH,0);
printf("send out message:%s./n",buffer);
sleep(1);
}
memset(buffer,0,MSG_LENGTH);
sprintf(buffer,"quit");
mq_send(mqid,buffer,MSG_LENGTH,0);
mq_close(mqid);
printf("now send thread quit./n");
return;
}
void msgReceiveThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
mqd_t mqid;
struct mq_attr privateAttr;
char buffer[MSG_LENGTH]={0};
mode_t mode;
mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
mqid=mq_open(para->msgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
if(mqid == -1)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("ReceiveThread:open msqueue failed!/n");
return;
}
unsigned int nreads=0;
for(;;)
{
mq_getattr(mqid,&privateAttr);
while(privateAttr.mq_curmsgs>0)
{
cread:
nreads=mq_receive(mqid,buffer,MSG_LENGTH,NULL);
if(strncmp(buffer,"quit",4) ==0 )
{
goto rend;
}
printf("/t/tread %d bytes,message is:%s./n",nreads,buffer);
mq_getattr(mqid,&privateAttr);
}
goto cread;
}
rend:
mq_unlink(para->msgQueueName);
mq_close(mqid);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct parameters myPara;
memset((void *)&myPara,0,sizeof(struct parameters));
strncat(myPara.msgQueueName,MSGQUEUE_NAME,MAXMSGNAMELENGTH);
//myPara.msgattr.mq_flags=O_RDWR|O_CREAT|O_NONBLOCK;
myPara.msgattr.mq_flags=O_RDWR|O_CREAT;
myPara.msgattr.mq_maxmsg=MSGQUEUE_LENGTH;
myPara.msgattr.mq_msgsize=MSG_LENGTH;
myPara.msgattr.mq_curmsgs=0;
myPara.timeInterval=1;
pthread_t pids;
pthread_t pidr;
pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
pthread_join(pids,NULL);
pthread_join(pidr,NULL);
printf("now main thread quit./n");
return 0;
}
二.mmap的问题:
因为前面的posix的消息队列的问题慢慢就觉得posix毕竟还是不如sysV在unix系列的操作系统上来得通用,然后先把sysV的ipc方式都试 用了一遍再试用posix方式的时候,犯了思维惯性的错误。因为sysV的share memory方式是“自动扩展”的(或者是达到一种“自动扩展”的效果),所以在试用posix方式shm的时候没有注意mmap是不具备“自动扩展”功 能的,所以就一直卡在“总线错误”这个运行错误上。其实说起来这个错误提示也是有点怪,google了很久也没有明确的说明。好在最后还是搞定了。
程序清单:posixshm.c
#include <sys/types.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <mqueue.h>
#include "myerr.h"
#define SEM_WRITER "/tmptestllsemw"
#define SEM_READER "/tmptestllsemr"
#define SHM_NAME "/tmptestllshm"
#define SHMSIZE 64
struct ThreadPara
{
sem_t * reader;
sem_t * writer;
int shmid;
int shmsize;
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
char * buffer;
buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_WRITE,MAP_SHARED,myPa->shmid,0);
printf("writer:get buffer address is:%x./n",(unsigned int)buffer);
for(counter=0;counter<10;counter++)
{
sem_wait(myPa->writer);
sprintf((char *)buffer,"this is the posix shm #%d message",counter);
sem_post(myPa->reader);
sleep(1);
}
sem_wait(myPa->writer);
memset(buffer,0,myPa->shmsize);
sprintf(buffer,"quitnow");
sem_post(myPa->reader);
munmap(buffer,myPa->shmsize);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_READ,MAP_SHARED,myPa->shmid,0);
printf("reader:get buffer address is:%x./n",(unsigned int )buffer);
for(;;)
{
sem_wait(myPa->reader);
if(strncmp((char *)buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./tthis is shm realization./n",(char *)buffer);
sem_post(myPa->writer);
}
munmap(buffer,myPa->shmsize);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
mode_t oMode;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=O_CREAT;
oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
if(myPara.reader <= 0)
{
printf("get semr err!/n");
judgeErr(errno);
goto cleanup;
}
myPara.writer=sem_open(SEM_WRITER,oFlag,oMode,1);
if(myPara.writer <= 0)
{
printf("get semw err!/n");
judgeErr(errno);
goto cleanup;
}
oFlag=O_CREAT|O_RDWR;
myPara.shmid=shm_open(SHM_NAME,oFlag,oMode);
if(myPara.shmid < 0)
{
printf("get shm err!/n");
judgeErr(errno);
goto cleanup;
}
printf("shmid:%d./n",myPara.shmid);
if(lseek(myPara.shmid,SHMSIZE-1,SEEK_SET)<0)
{
printf("lseek error./n");
}
if(write(myPara.shmid,"",1)!=1)
{
printf("write error./n");
}
myPara.shmsize=SHMSIZE;
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
cleanup:
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
shm_unlink(SHM_NAME);
printf("main thread quit now./n");
return 0;
}
三.如果是简单的信号量的使用的话还是posix的信号量用起来简单一些,和mutex有点象吧。
最 后:其他没什么问题。一些说明就是虽然这里说的ipc的问题,但是到底是将多个工作流程实现为多进程,还是将多个工作流程实现为多线程。还是具体问题具体 分析吧,比如考虑到实时性,考虑的进程轮换的开销等等,不过大致的想来似乎是一样,按照“内核线程”的模型,多线程似乎还节省了进程切换的开销呢。呵呵。 先这么臆断吧,也不知道是不是正确的,有机会测试一下。
而这里图个方便,就全部都是采用开线程测试的。也是做个备忘的意思,几个程序的清单如下:
sysvqueue.c
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define MSGQUEUE_NAME "/tmp/tllmsgqueue"
#define MSGQUEUE_ID 0
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
key_t mqid;
struct msqid_ds qds;
int oflag;
};
void msgSendThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
int mqid;
char buffer[MSG_LENGTH]={0};
unsigned int counter=0;
mqid=msgget(para->mqid,para->oflag);
if(mqid == -1)
{
return;
}
for(;counter<10;counter++)
{
sprintf(buffer,"this is the #%d message",counter);
msgsnd(mqid,buffer,MSG_LENGTH,0);
sleep(1);
}
memset(buffer,0,MSG_LENGTH);
sprintf(buffer,"quit");
msgsnd(mqid,buffer,MSG_LENGTH,0);
//msgctl(mqid,IPC_RMID,NULL);
printf("send thread quit now./n");
return;
}
void msgReceiveThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
int mqid;
char buffer[MSG_LENGTH]={0};
mqid=msgget(para->mqid,para->oflag);
if(mqid == -1)
{
return;
}
unsigned int nreads=0;
for(;;)
{
msgctl(mqid,IPC_STAT,&(para->qds));
while(para->qds.msg_qnum>0)
{
doread:
nreads=msgrcv(mqid,buffer,MSG_LENGTH,0,0);
if(errno == EIDRM)
{
goto abquit;
}
if(strncmp(buffer,"quit",4)==0)
{
goto endreceive;
}
printf("read %hd bytes,message is:%s./n",nreads,buffer);
msgctl(mqid,IPC_STAT,&(para->qds));
}
goto doread;
}
endreceive:
msgctl(mqid,IPC_RMID,NULL);
abquit:
printf("receive thread quit now ./n");
return;
}
int main(void)
{
struct parameters myPara;
memset((void *)&myPara,0,sizeof(struct parameters));
#ifdef PRIVATEIPC
myPara.mqid=IPC_PRIVATE;
#else
myPara.mqid=ftok(MSGQUEUE_NAME,MSGQUEUE_ID);
#endif
myPara.oflag=IPC_CREAT;
pthread_t pids;
pthread_t pidr;
pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
pthread_join(pidr,NULL);
//printf("/tnow is here!/n");
pthread_join(pids,NULL);
printf("main thread quit now./n");
return 0;
}
sysvsem.c
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define BUFFERSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
/* Linux specific part: */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
key_t kid;
int semid;
unsigned int readerIndex;
unsigned int writerIndex;
char buffer[BUFFERSIZE];
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
for(;counter<10;counter++)
{
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=SEM_UNDO;
semop(myPa->semid,&semops,1);
sprintf(myPa->buffer,"this is the #%d message",counter);
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
//sleep(1);
}
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
memset(myPa->buffer,0,BUFFERSIZE);
sprintf(myPa->buffer,"quitnow");
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
for(;;)
{
semops.sem_num=myPa->readerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
if(strncmp(myPa->buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./n",myPa->buffer);
semops.sem_num=myPa->writerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
}
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
//mode_t oMode;
union semun arg;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=IPC_CREAT|IPC_EXCL;
//oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
myPara.kid=IPC_PRIVATE;
#else
myPara.kid=ftok(SEM_NAME,SEM_ID);
#endif
myPara.semid=semget(myPara.kid,2,oFlag);
myPara.readerIndex=0;
myPara.writerIndex=1;
arg.val=0;
semctl(myPara.semid,myPara.readerIndex,SETVAL,arg);
arg.val=1;
semctl(myPara.semid,myPara.writerIndex,SETVAL,arg);
if(myPara.semid < 0)
{
if(errno == EEXIST)
{
printf("get sem err!/n");
}
}
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
semctl(myPara.semid,0,IPC_RMID);
printf("now main thread quit./n");
return 0;
}
sysvshm.c
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define SHM_NAME "/tmp/testllshm"
#define SHM_ID 0
#define SHMSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
/* Linux specific part: */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
key_t ksemid;
key_t kshmid;
int semid;
int shmid;
unsigned int readerIndex;
unsigned int writerIndex;
int shmsize;
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
buffer=shmat(myPa->shmid,NULL,0);
for(;counter<10;counter++)
{
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=SEM_UNDO;
semop(myPa->semid,&semops,1);
sprintf(buffer,"this is the #%d message",counter);
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
//sleep(1);
}
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
memset(buffer,0,myPa->shmsize);
sprintf(buffer,"quitnow");
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
shmdt(buffer);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
buffer=shmat(myPa->shmid,NULL,SHM_RDONLY);
for(;;)
{
semops.sem_num=myPa->readerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
if(strncmp(buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./tthis is shm realization./n",(char *)buffer);
semops.sem_num=myPa->writerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
}
shmdt(buffer);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
//mode_t oMode;
union semun arg;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=IPC_CREAT|IPC_EXCL;
//oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
myPara.ksemid=IPC_PRIVATE;
myPara.kshmid=IPC_PRIVATE;
#else
myPara.ksemid=ftok(SEM_NAME,SEM_ID);
myPara.kshmid=ftok(SHM_NAME,SHM_ID);
#endif
myPara.shmsize=SHMSIZE;
myPara.semid=semget(myPara.ksemid,2,oFlag);
if(myPara.semid < 0)
{
if(errno == EEXIST)
{
printf("get sem err!/n");
}
}
myPara.shmid=shmget(myPara.kshmid,myPara.shmsize,oFlag);
if(myPara.shmid < 0)
{
if(errno == EEXIST)
{
printf("get shm err!/n");
}
}
myPara.readerIndex=0;
myPara.writerIndex=1;
arg.val=0;
semctl(myPara.semid,myPara.readerIndex,SETVAL,arg);
arg.val=1;
semctl(myPara.semid,myPara.writerIndex,SETVAL,arg);
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
semctl(myPara.semid,0,IPC_RMID);
shmctl(myPara.shmid,IPC_RMID,NULL);
printf("main thread quit now./n");
return 0;
}
posixsem.c
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <errno.h>
#define SEM_WRITER "/testllposixsemw"
#define SEM_READER "/testllposixsemr"
#define BUFFERSIZE 64
struct ThreadPara
{
sem_t * reader;
sem_t * writer;
char buffer[BUFFERSIZE];
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
for(;counter<10;counter++)
{
sem_wait(myPa->writer);
sprintf(myPa->buffer,"writer:this is the POSIX_SEM #%d message",counter);
sem_post(myPa->reader);
//sleep(1);
}
sem_wait(myPa->writer);
memset(myPa->buffer,0,BUFFERSIZE);
sprintf(myPa->buffer,"quitnow");
sem_post(myPa->reader);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
for(;;)
{
sem_wait(myPa->reader);
if(strncmp(myPa->buffer,"quitnow",7) == 0)
{
break;
}
printf("/treader:Yes,i got buffer:%s./n",myPa->buffer);
sem_post(myPa->writer);
//sleep(3);
}
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
mode_t oMode;
memset(&myPara,0,sizeof(struct ThreadPara));
//oFlag=O_CREAT|O_EXCL;
oFlag=O_CREAT;
oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
if(myPara.reader <= 0)
{
printf("failed to open sem reader/n");
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
return -1;
}
myPara.writer=sem_open(SEM_WRITER,oFlag,oMode,1);
if(myPara.writer <= 0)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("failed to open sem writer/n");
}
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
sem_close(myPara.reader);
sem_close(myPara.writer);
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
printf("now main thread quit./n");
return 0;
}
外加一个简陋的Makefile。
CFLAGS=-O9 -Wall -g -D__POSIX_SOURCE
CINCLUDES=
CLIBS=-lpthread -lrt
POSIXQUEUELIB=-lmqueue
CC=gcc
all:tm one two tcrc pq vq psem vsem vshm pshm
pshm:posixshm.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o pshm posixshm.c
vshm:sysvshm.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vshm sysvshm.c
psem:posixsem.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o psem posixsem.c
vsem:sysvsem.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vsem sysvsem.c
vq:sysvqueue.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vq sysvqueue.c
pq:posixqueue.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) $(POSIXQUEUELIB) -o pq posixqueue.c
tcrc:testcrc.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tcrc testcrc.c
tm:testmain.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tm testmain.c
one:one.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o one one.c
two:two.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o two two.c
clean:
rm -f vshm
rm -f pshm
rm -f vsem
rm -f psem
rm -f pq
rm -f vq
rm -f tcrc
rm -f one
rm -f two
rm -f tm
rm -f a.out
留此备忘
最近整理了一下几种ipc方式的使用,一些小问题,在此存档:
一.posix的msgqueue的支持问题。
要说明的是从一开始就觉得所谓的posix的兼容是很好的一个东西,而linux对posix的兼容性很好也是一直以来发展linuxer的一个重要的游 说砝码。但是在开始测试posix message queue的时候遭到了当头一棒。程序编译通过,连接出错!然后google到nptl的知识,声称posix msgqueue的支持在mm分支中发展。晕先。不甘心的同时在新下载的2.6.18里面发现了如下说明:
2.6.18的内核里面关于posix message-queue的选项说明:
CONFIG_POSIX_MQUEUE:
POSIX variant of message queues is a part of IPC. In POSIX message
queues every message has a priority which decides about succession
of receiving it by a process. If you want to compile and run
programs written e.g. for Solaris with use of its POSIX message
queues (functions mq_*) say Y here. To use this feature you will
also need mqueue library, available from
<http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
POSIX message queues are visible as a filesystem called 'mqueue'
and can be mounted somewhere if you want to do filesystem
operations on message queues.
If unsure, say Y.
Symbol: POSIX_MQUEUE [=y]
Prompt: POSIX Message Queues
Defined at init/Kconfig:118
Depends on: NET && EXPERIMENTAL
同时在2.6.16里面这个还是没有的,真是庆幸啊,要是早点开始关注这个岂不是要郁闷很久或者麻烦很久。遵照上面内核编译系统给出的信息,上网站一看原 来已经转到了:http://www.geocities.com/wronski12/posix_ipc/index.html.下载了: libmqueue-4.41.tar.gz。经典的三步之后再编译。bingle!
程序清单:posixqueue.c
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#define MSGQUEUE_NAME "/tllmsgqueue"
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
char msgQueueName[MAXMSGNAMELENGTH];
struct mq_attr msgattr;
unsigned int timeInterval;
};
void msgSendThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
mq_unlink(para->msgQueueName);
mqd_t mqid;
char buffer[MSG_LENGTH]={0};
unsigned int counter=0;
mode_t mode;
mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
mqid=mq_open(para->msgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
if(mqid == -1)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("SendThread:open msqueue failed!/n");
return;
}
for(;counter<10;counter++)
{
sprintf(buffer,"this is the #%d message",counter);
mq_send(mqid,buffer,MSG_LENGTH,0);
printf("send out message:%s./n",buffer);
sleep(1);
}
memset(buffer,0,MSG_LENGTH);
sprintf(buffer,"quit");
mq_send(mqid,buffer,MSG_LENGTH,0);
mq_close(mqid);
printf("now send thread quit./n");
return;
}
void msgReceiveThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
mqd_t mqid;
struct mq_attr privateAttr;
char buffer[MSG_LENGTH]={0};
mode_t mode;
mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
mqid=mq_open(para->msgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
if(mqid == -1)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("ReceiveThread:open msqueue failed!/n");
return;
}
unsigned int nreads=0;
for(;;)
{
mq_getattr(mqid,&privateAttr);
while(privateAttr.mq_curmsgs>0)
{
cread:
nreads=mq_receive(mqid,buffer,MSG_LENGTH,NULL);
if(strncmp(buffer,"quit",4) ==0 )
{
goto rend;
}
printf("/t/tread %d bytes,message is:%s./n",nreads,buffer);
mq_getattr(mqid,&privateAttr);
}
goto cread;
}
rend:
mq_unlink(para->msgQueueName);
mq_close(mqid);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct parameters myPara;
memset((void *)&myPara,0,sizeof(struct parameters));
strncat(myPara.msgQueueName,MSGQUEUE_NAME,MAXMSGNAMELENGTH);
//myPara.msgattr.mq_flags=O_RDWR|O_CREAT|O_NONBLOCK;
myPara.msgattr.mq_flags=O_RDWR|O_CREAT;
myPara.msgattr.mq_maxmsg=MSGQUEUE_LENGTH;
myPara.msgattr.mq_msgsize=MSG_LENGTH;
myPara.msgattr.mq_curmsgs=0;
myPara.timeInterval=1;
pthread_t pids;
pthread_t pidr;
pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
pthread_join(pids,NULL);
pthread_join(pidr,NULL);
printf("now main thread quit./n");
return 0;
}
二.mmap的问题:
因为前面的posix的消息队列的问题慢慢就觉得posix毕竟还是不如sysV在unix系列的操作系统上来得通用,然后先把sysV的ipc方式都试 用了一遍再试用posix方式的时候,犯了思维惯性的错误。因为sysV的share memory方式是“自动扩展”的(或者是达到一种“自动扩展”的效果),所以在试用posix方式shm的时候没有注意mmap是不具备“自动扩展”功 能的,所以就一直卡在“总线错误”这个运行错误上。其实说起来这个错误提示也是有点怪,google了很久也没有明确的说明。好在最后还是搞定了。
程序清单:posixshm.c
#include <sys/types.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <mqueue.h>
#include "myerr.h"
#define SEM_WRITER "/tmptestllsemw"
#define SEM_READER "/tmptestllsemr"
#define SHM_NAME "/tmptestllshm"
#define SHMSIZE 64
struct ThreadPara
{
sem_t * reader;
sem_t * writer;
int shmid;
int shmsize;
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
char * buffer;
buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_WRITE,MAP_SHARED,myPa->shmid,0);
printf("writer:get buffer address is:%x./n",(unsigned int)buffer);
for(counter=0;counter<10;counter++)
{
sem_wait(myPa->writer);
sprintf((char *)buffer,"this is the posix shm #%d message",counter);
sem_post(myPa->reader);
sleep(1);
}
sem_wait(myPa->writer);
memset(buffer,0,myPa->shmsize);
sprintf(buffer,"quitnow");
sem_post(myPa->reader);
munmap(buffer,myPa->shmsize);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_READ,MAP_SHARED,myPa->shmid,0);
printf("reader:get buffer address is:%x./n",(unsigned int )buffer);
for(;;)
{
sem_wait(myPa->reader);
if(strncmp((char *)buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./tthis is shm realization./n",(char *)buffer);
sem_post(myPa->writer);
}
munmap(buffer,myPa->shmsize);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
mode_t oMode;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=O_CREAT;
oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
if(myPara.reader <= 0)
{
printf("get semr err!/n");
judgeErr(errno);
goto cleanup;
}
myPara.writer=sem_open(SEM_WRITER,oFlag,oMode,1);
if(myPara.writer <= 0)
{
printf("get semw err!/n");
judgeErr(errno);
goto cleanup;
}
oFlag=O_CREAT|O_RDWR;
myPara.shmid=shm_open(SHM_NAME,oFlag,oMode);
if(myPara.shmid < 0)
{
printf("get shm err!/n");
judgeErr(errno);
goto cleanup;
}
printf("shmid:%d./n",myPara.shmid);
if(lseek(myPara.shmid,SHMSIZE-1,SEEK_SET)<0)
{
printf("lseek error./n");
}
if(write(myPara.shmid,"",1)!=1)
{
printf("write error./n");
}
myPara.shmsize=SHMSIZE;
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
cleanup:
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
shm_unlink(SHM_NAME);
printf("main thread quit now./n");
return 0;
}
三.如果是简单的信号量的使用的话还是posix的信号量用起来简单一些,和mutex有点象吧。
最 后:其他没什么问题。一些说明就是虽然这里说的ipc的问题,但是到底是将多个工作流程实现为多进程,还是将多个工作流程实现为多线程。还是具体问题具体 分析吧,比如考虑到实时性,考虑的进程轮换的开销等等,不过大致的想来似乎是一样,按照“内核线程”的模型,多线程似乎还节省了进程切换的开销呢。呵呵。 先这么臆断吧,也不知道是不是正确的,有机会测试一下。
而这里图个方便,就全部都是采用开线程测试的。也是做个备忘的意思,几个程序的清单如下:
sysvqueue.c
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define MSGQUEUE_NAME "/tmp/tllmsgqueue"
#define MSGQUEUE_ID 0
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
key_t mqid;
struct msqid_ds qds;
int oflag;
};
void msgSendThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
int mqid;
char buffer[MSG_LENGTH]={0};
unsigned int counter=0;
mqid=msgget(para->mqid,para->oflag);
if(mqid == -1)
{
return;
}
for(;counter<10;counter++)
{
sprintf(buffer,"this is the #%d message",counter);
msgsnd(mqid,buffer,MSG_LENGTH,0);
sleep(1);
}
memset(buffer,0,MSG_LENGTH);
sprintf(buffer,"quit");
msgsnd(mqid,buffer,MSG_LENGTH,0);
//msgctl(mqid,IPC_RMID,NULL);
printf("send thread quit now./n");
return;
}
void msgReceiveThread(void * data)
{
//pthread_detach(pthread_self());
struct parameters * para=(struct parameters *)data;
int mqid;
char buffer[MSG_LENGTH]={0};
mqid=msgget(para->mqid,para->oflag);
if(mqid == -1)
{
return;
}
unsigned int nreads=0;
for(;;)
{
msgctl(mqid,IPC_STAT,&(para->qds));
while(para->qds.msg_qnum>0)
{
doread:
nreads=msgrcv(mqid,buffer,MSG_LENGTH,0,0);
if(errno == EIDRM)
{
goto abquit;
}
if(strncmp(buffer,"quit",4)==0)
{
goto endreceive;
}
printf("read %hd bytes,message is:%s./n",nreads,buffer);
msgctl(mqid,IPC_STAT,&(para->qds));
}
goto doread;
}
endreceive:
msgctl(mqid,IPC_RMID,NULL);
abquit:
printf("receive thread quit now ./n");
return;
}
int main(void)
{
struct parameters myPara;
memset((void *)&myPara,0,sizeof(struct parameters));
#ifdef PRIVATEIPC
myPara.mqid=IPC_PRIVATE;
#else
myPara.mqid=ftok(MSGQUEUE_NAME,MSGQUEUE_ID);
#endif
myPara.oflag=IPC_CREAT;
pthread_t pids;
pthread_t pidr;
pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
pthread_join(pidr,NULL);
//printf("/tnow is here!/n");
pthread_join(pids,NULL);
printf("main thread quit now./n");
return 0;
}
sysvsem.c
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define BUFFERSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
/* Linux specific part: */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
key_t kid;
int semid;
unsigned int readerIndex;
unsigned int writerIndex;
char buffer[BUFFERSIZE];
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
for(;counter<10;counter++)
{
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=SEM_UNDO;
semop(myPa->semid,&semops,1);
sprintf(myPa->buffer,"this is the #%d message",counter);
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
//sleep(1);
}
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
memset(myPa->buffer,0,BUFFERSIZE);
sprintf(myPa->buffer,"quitnow");
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
for(;;)
{
semops.sem_num=myPa->readerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
if(strncmp(myPa->buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./n",myPa->buffer);
semops.sem_num=myPa->writerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
}
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
//mode_t oMode;
union semun arg;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=IPC_CREAT|IPC_EXCL;
//oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
myPara.kid=IPC_PRIVATE;
#else
myPara.kid=ftok(SEM_NAME,SEM_ID);
#endif
myPara.semid=semget(myPara.kid,2,oFlag);
myPara.readerIndex=0;
myPara.writerIndex=1;
arg.val=0;
semctl(myPara.semid,myPara.readerIndex,SETVAL,arg);
arg.val=1;
semctl(myPara.semid,myPara.writerIndex,SETVAL,arg);
if(myPara.semid < 0)
{
if(errno == EEXIST)
{
printf("get sem err!/n");
}
}
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
semctl(myPara.semid,0,IPC_RMID);
printf("now main thread quit./n");
return 0;
}
sysvshm.c
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define SHM_NAME "/tmp/testllshm"
#define SHM_ID 0
#define SHMSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
/* Linux specific part: */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
key_t ksemid;
key_t kshmid;
int semid;
int shmid;
unsigned int readerIndex;
unsigned int writerIndex;
int shmsize;
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
buffer=shmat(myPa->shmid,NULL,0);
for(;counter<10;counter++)
{
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=SEM_UNDO;
semop(myPa->semid,&semops,1);
sprintf(buffer,"this is the #%d message",counter);
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
//sleep(1);
}
semops.sem_num=myPa->writerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
memset(buffer,0,myPa->shmsize);
sprintf(buffer,"quitnow");
semops.sem_num=myPa->readerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
shmdt(buffer);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
void * buffer;
struct sembuf semops;
semops.sem_flg=SEM_UNDO;
buffer=shmat(myPa->shmid,NULL,SHM_RDONLY);
for(;;)
{
semops.sem_num=myPa->readerIndex;
semops.sem_op=-1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
if(strncmp(buffer,"quitnow",7) == 0)
{
break;
}
printf("/tYes,i got buffer:%s./tthis is shm realization./n",(char *)buffer);
semops.sem_num=myPa->writerIndex;
semops.sem_op=1;
//semops.sem_flg=0;
semop(myPa->semid,&semops,1);
}
shmdt(buffer);
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
//mode_t oMode;
union semun arg;
memset(&myPara,0,sizeof(struct ThreadPara));
oFlag=IPC_CREAT|IPC_EXCL;
//oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
myPara.ksemid=IPC_PRIVATE;
myPara.kshmid=IPC_PRIVATE;
#else
myPara.ksemid=ftok(SEM_NAME,SEM_ID);
myPara.kshmid=ftok(SHM_NAME,SHM_ID);
#endif
myPara.shmsize=SHMSIZE;
myPara.semid=semget(myPara.ksemid,2,oFlag);
if(myPara.semid < 0)
{
if(errno == EEXIST)
{
printf("get sem err!/n");
}
}
myPara.shmid=shmget(myPara.kshmid,myPara.shmsize,oFlag);
if(myPara.shmid < 0)
{
if(errno == EEXIST)
{
printf("get shm err!/n");
}
}
myPara.readerIndex=0;
myPara.writerIndex=1;
arg.val=0;
semctl(myPara.semid,myPara.readerIndex,SETVAL,arg);
arg.val=1;
semctl(myPara.semid,myPara.writerIndex,SETVAL,arg);
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
semctl(myPara.semid,0,IPC_RMID);
shmctl(myPara.shmid,IPC_RMID,NULL);
printf("main thread quit now./n");
return 0;
}
posixsem.c
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <errno.h>
#define SEM_WRITER "/testllposixsemw"
#define SEM_READER "/testllposixsemr"
#define BUFFERSIZE 64
struct ThreadPara
{
sem_t * reader;
sem_t * writer;
char buffer[BUFFERSIZE];
};
void writerThread(void * data)
{
unsigned int counter=0;
struct ThreadPara * myPa=(struct ThreadPara *)data;
for(;counter<10;counter++)
{
sem_wait(myPa->writer);
sprintf(myPa->buffer,"writer:this is the POSIX_SEM #%d message",counter);
sem_post(myPa->reader);
//sleep(1);
}
sem_wait(myPa->writer);
memset(myPa->buffer,0,BUFFERSIZE);
sprintf(myPa->buffer,"quitnow");
sem_post(myPa->reader);
printf("now send thread quit./n");
return;
}
void readerThread(void * data)
{
struct ThreadPara * myPa=(struct ThreadPara *)data;
for(;;)
{
sem_wait(myPa->reader);
if(strncmp(myPa->buffer,"quitnow",7) == 0)
{
break;
}
printf("/treader:Yes,i got buffer:%s./n",myPa->buffer);
sem_post(myPa->writer);
//sleep(3);
}
printf("now receive thread quit./n");
return;
}
int main(void)
{
struct ThreadPara myPara;
int oFlag;
mode_t oMode;
memset(&myPara,0,sizeof(struct ThreadPara));
//oFlag=O_CREAT|O_EXCL;
oFlag=O_CREAT;
oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
if(myPara.reader <= 0)
{
printf("failed to open sem reader/n");
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
return -1;
}
myPara.writer=sem_open(SEM_WRITER,oFlag,oMode,1);
if(myPara.writer <= 0)
{
switch(errno)
{
case EACCES:
printf("EACCES------------/n");
break;
case EEXIST:
printf("EEXIST------------/n");
break;
case EINTR:
printf("EINTR------------/n");
break;
case EINVAL:
printf("EINVAL------------/n");
break;
case ENAMETOOLONG:
printf("ENAMETOOLONG------------/n");
case ENOENT:
printf("ENOENT------------/n");
break;
case ENOMEM:
printf("ENOMEM------------/n");
break;
case ENOSPC:
printf("ENOSPC------------/n");
break;
case EFAULT:
printf("EFAULT------------/n");
break;
case EMFILE:
printf("EMFILE------------/n");
break;
case ENFILE:
printf("ENFILE------------/n");
break;
default:
break;
}
printf("failed to open sem writer/n");
}
pthread_t pidr;
pthread_t pidw;
pthread_create(&pidr,NULL,(void *)readerThread,&myPara);
pthread_create(&pidw,NULL,(void *)writerThread,&myPara);
pthread_join(pidr,NULL);
pthread_join(pidw,NULL);
sem_close(myPara.reader);
sem_close(myPara.writer);
sem_unlink(SEM_READER);
sem_unlink(SEM_WRITER);
printf("now main thread quit./n");
return 0;
}
外加一个简陋的Makefile。
CFLAGS=-O9 -Wall -g -D__POSIX_SOURCE
CINCLUDES=
CLIBS=-lpthread -lrt
POSIXQUEUELIB=-lmqueue
CC=gcc
all:tm one two tcrc pq vq psem vsem vshm pshm
pshm:posixshm.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o pshm posixshm.c
vshm:sysvshm.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vshm sysvshm.c
psem:posixsem.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o psem posixsem.c
vsem:sysvsem.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vsem sysvsem.c
vq:sysvqueue.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vq sysvqueue.c
pq:posixqueue.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) $(POSIXQUEUELIB) -o pq posixqueue.c
tcrc:testcrc.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tcrc testcrc.c
tm:testmain.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tm testmain.c
one:one.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o one one.c
two:two.c
$(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o two two.c
clean:
rm -f vshm
rm -f pshm
rm -f vsem
rm -f psem
rm -f pq
rm -f vq
rm -f tcrc
rm -f one
rm -f two
rm -f tm
rm -f a.out
留此备忘
- Linux IPC备忘
- linux IPC
- Linux IPC
- linux ipc
- linux ipc
- Linux IPC
- Linux IPC
- Linux IPC
- Linux IPC
- Linux备忘
- Linux备忘
- Linux 备忘
- Linux 备忘
- Linux备忘
- Linux备忘
- Linux备忘
- linux备忘
- Linux备忘
- 智能指针单例模式的实现
- 慎用Enum的ToString
- 学习foreach
- Dreamweaver制作网页经典问题大整理
- 20070929听力原文
- Linux IPC备忘
- 字符,字节和编码
- DataGrid自定义导航按钮
- ASP.NET网络应用与开发实践教程 - 图书目录
- SQL Server 2005的30个最重要特点
- Office文档在线编辑的实现之一
- 网络诊断工具MegaPing 给网管员减负
- 偶遇 BHDCRegC.exe, IEBHO.dll, IETool.dll 等
- getopt()函数简介