beijibing@bjb-desktop:~$ cat /mnt/mymq QSIZE:1 NOTIFY:2 SIGNO:0 NOTIFY_PID:2719 beijibing@bjb-desktop:~$ ls -al /mnt 总用量 4 drwxrwxrwt 2 root root 60 2012-08-22 21:18 . drwxr-xr-x 22 root root 4096 2012-05-08 00:16 .. -rw-r--r-- 1 beijibing beijibing 80 2012-08-22 21:20 mymq 原文链接:http://home./home-space-uid-56821-do-blog-id-233077.html POSIX IPC为每个对象都使用文件描述符,这与System V的IPC不同,System V的每个对象都使用键值(keys).由于每个IPC对象可以写到一个纯文本文件,因此,在纯文本文件上使用的工具对于操作POSIX IPC对象来说通常已经足够了. 1)POSIX共享内存 在Linux中,POSIX共享内存对象驻留在tmpfs伪文件系统中.系统默认挂载在/dev/shm目录下. 当调用shm_open函数创建或打开POSIX共享内存对象时,系统会将创建/打开的共享内存文件放到/dev/shm目录下. 同样也可以手工在/dev/shm目录下创建文件,以供POSIX共享内存程序连接使用. 我们用下面的源程序对POSIX共享内存进行测试,如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/file.h> #include <sys/mman.h> #include <sys/wait.h> void error_out(const char *msg) { perror(msg); exit(EXIT_FAILURE); } int main (int argc, char *argv[]) { int r; const char *memname = "/mymem"; const size_t region_size = sysconf(_SC_PAGE_SIZE); int fd = shm_open(memname, O_CREAT|O_TRUNC|O_RDWR, 0666); if (fd == -1) error_out("shm_open"); r = ftruncate(fd, region_size); if (r != 0) error_out("ftruncate"); void *ptr = mmap(0, region_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) error_out("MMAP"); close(fd); pid_t pid = fork(); if (pid == 0){ u_long *d = (u_long *)ptr; *d = 0xdeadbeef; exit(0); } else{ int status; waitpid(pid, &status, 0); printf("child wrote %#lx\n", *(u_long *)ptr); } sleep(50); r = munmap(ptr, region_size); if (r != 0) error_out("munmap"); r = shm_unlink(memname); if (r != 0) error_out("shm_unlink"); return 0; } 编译程序pmem.c gcc pmem.c -o pmem -lrt 执行程序pmem ./pmem child wrote 0xdeadbeef 注:程序会通过shm_open函数创建一个共享内存对象,并通过mmap函数将文件映射到内存,此时修改内存,即是修改文件. 子进程向共享内存写数据,父进程将共享内存数据打印输出,在输出完成后,会等待50秒钟.我们可以在另一个终端看到/dev/shm/mymem文件,如下: ls -l /dev/shm/mymem -rw-r--r-- 1 root root 4096 2011-03-16 15:22 /dev/shm/mymem 2)POSIX消息队列 在Linux中通过mqueue伪文件系统来显示POSIX消息队列,与POSIX共享内存不同的是,它没有一个标准的挂载点来为这个文件系统服务. 如果需要调试来自shell的POSIX消息队列,则需要手动挂载文件系统,例如,为了将其挂载在命名为/mnt/mqs的目录下,可以使用以下命令: mkdir /mnt/mqs mount -t mqueue none /mnt/mqs 我们用下面的源程序对POSIX消息队列进行测试,如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <mqueue.h> #include <sys/stat.h> #include <sys/wait.h> struct message{ char mtext[128]; }; int send_msg(int qid, int pri, const char text[]) { int r = mq_send(qid, text, strlen(text) + 1,pri); if (r == -1){ perror("mq_send"); } return r; } void producer(mqd_t qid) { send_msg(qid, 1, "This is my first message."); send_msg(qid, 1, "This is my second message."); send_msg(qid, 3, "No more messages."); } void consumer(mqd_t qid) { struct mq_attr mattr; do{ u_int pri; struct message msg; ssize_t len; len = mq_receive(qid, (char *)&msg, sizeof(msg), &pri); if (len == -1){ perror("mq_receive"); break; } printf("got pri %d '%s' len=%d\n", pri, msg.mtext, len); int r = mq_getattr(qid, &mattr); if (r == -1){ perror("mq_getattr"); break; } }while(mattr.mq_curmsgs); } int main (int argc, char *argv[]) { struct mq_attr mattr = { .mq_maxmsg = 10, .mq_msgsize = sizeof(struct message) }; mqd_t mqid = mq_open("/myq", O_CREAT|O_RDWR, S_IREAD|S_IWRITE, &mattr); if (mqid == (mqd_t) -1){ perror("mq_open"); exit (1); } pid_t pid = fork(); if (pid == 0){ producer(mqid); mq_close(mqid); exit(0); } else { int status; wait(&status); sleep(50); consumer(mqid); mq_close(mqid); } mq_unlink("/myq"); return 0; } 编译: gcc posix_mqs.c -o posix_mqs -lrt 运行程序: ./posix_mqs got pri 3 'No more messages.' len=18 got pri 1 'This is my first message.' len=26 got pri 1 'This is my second message.' len=27 注:程序通过fork使子进程发送三条消息到消息队列,父进程从消息队列中接收这三条消息. /mnt/mqs/myq文件是程序创建的消息队列文件,程序会自动在伪文件系统mqueue中创建消息队列文件. 如果我们挂载伪文件系统到多个目录,而在每个挂载目录下都会生成消息队列文件. 例如: mkdir /dev/mqs/ mount -t mqueue none /dev/mqs df -aTh Filesystem Type Size Used Avail Use% Mounted on /dev/sda1 ext3 19G 3.3G 15G 19% / proc proc 0 0 0 - /proc sysfs sysfs 0 0 0 - /sys devpts devpts 0 0 0 - /dev/pts tmpfs tmpfs 512M 0 512M 0% /dev/shm none binfmt_misc 0 0 0 - /proc/sys/fs/binfmt_misc sunrpc rpc_pipefs 0 0 0 - /var/lib/nfs/rpc_pipefs none mqueue 0 0 0 - /mnt/mqs none mqueue 0 0 0 - /dev/mqs 再次运行程序 ./posix_mqs 我们看到在两个mqueue伪文件系统挂载的目录下都生成了myq文件 cat /mnt/mqs/myq /dev/mqs/myq QSIZE:71 NOTIFY:0 SIGNO:0 NOTIFY_PID:0 QSIZE:71 NOTIFY:0 SIGNO:0 NOTIFY_PID:0 QSIZE:71表示/mnt/mqs/myq消息队列中一共有71个字节. NOTIFY,SIGNO,NOTIFY_PID都和mq_notify函数有关. 3)POSIX信号量 在Linux中,POSIX信号量对象驻留在tmpfs伪文件系统中,同POSIX共享内存一样,有名字的信号量作为文件被创建在/dev/shm里. 我们用下面的源程序来测试POSIX信号量,如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/file.h> #include <sys/times.h> #include <sys/stat.h> #include <semaphore.h> #include <assert.h> void busywait(void) { clock_t t1 = times(NULL); while(times(NULL) - t1 < 2); } int main (int argc, char *argv[]) { const char *message = "Hello World\n"; int n = strlen(message)/2; sem_t *sem = sem_open("/thesem", O_CREAT, S_IRUSR|S_IWUSR); sleep(30); assert(sem != NULL); int r = sem_init(sem, 1, 0); assert(r == 0); pid_t pid = fork(); int i0 = (pid == 0) ? 0 :n ; int i; if (pid) sem_wait(sem); for (i = 0;i < n;i++){ write (1,message+i0+i,1); busywait(); } if (pid == 0) sem_post(sem); } 编译: gcc posix-sem.c -o posix-sem -lrt 执行posix-sem程序: ./posix-sem 在另一个终端查看信号量文件,如下: ls -l /dev/shm/ total 4 -rw------- 1 root root 16 Mar 18 10:32 sem.thesem 一个被命名为thesem的信号量出现在/dev/shm/sem.thesem Posix消息队列和System V消息队列主要的差别在于: Posix队列中消息具有以下的属性: 可将消息队列认为是一个消息链表,该链表的头中含有当前队列的两个属性:队列中允许的最大消息数以及每个消息的最大大小。消息队列具有虽内核的持续性。Posix消息队列常用的几个函数: #include<mqueue.h> mqd_t mq_open(const char *name,int oflag,... 当实际操作是创建一个新的队列时,则需要mode和attr参数。attr参数是用于给新的消息队列指定某些属性。 struct mq_attr { } 当attr参数为NULL时则使用默认值msg_max 10,msgsize_max 8192。而使用mq_open创建一个新的队列时,attr只能给它指定mq_maxmsg,mq_msgsize这两个属性。mq_open忽略 attr结构中的另外两个成员。在创建过程中需要注意的是,指定的这两个属性都必须小于等于msg_max或者msgsize_max的。查看系统中消息 队列的这两个限制值的方法是: cat /proc/sys/fs/mqueue/msg_max cat /proc/sys/fs/mqueue/msgsize_max 修改/etc/sysctl.conf 在这个文件中添加 #mqueue max fs.mqueue.msg_max=100 fs.mqueue.msgsize_max=9000 fs.mqueue.queues_max=520 保存好后重启系统就好了。 下面编写一个创建Posix消息队列的程序: #define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH int main(int argc,char **argv) { } [zd@zhengdan 消息队列]$ sudo mkdir /mnt [zd@zhengdan 消息队列]$ sudo mount -t mqueue none /mnt 这样就可以在/mnt下看到所创建的消息队列了,此时是以文件形式存在了。 [zd@zhengdan 消息队列]$ ls -l /mnt 总用量 0 -rw-r--r-- 1 zd zd 80 -rw-r--r-- 1 zd zd 80 -rw-r--r-- 1 zd zd 80 -rw-r--r-- 1 zd zd 80 1:在编译的时候要加上 -lrt 中的rt.so连接库,gcc mqcreatel.c -o mqcreatel -lrt 2:如果要查看创建的消息队列的文件, 需要挂载后才能看见,sudo mount -t mqueue none /mnt 则相应的消息队列文件在/mnt文件目录下. |
|