linux IPC。为什么msgrcv总是阻塞?
linux ipc. Why is msgrcv always blocking?
客户端 readline 写入共享 memory.and 向服务器发送消息。
服务器获取消息并从共享内存中读取。
但是服务器无法正确输出,
服务器没有任何输出,不知道为什么。
手册页说:
如果没有可用的请求类型的消息并且未在 msgflg 中指定 IPC_NOWAIT,则调用进程将被阻塞,直到出现以下情况之一
但是服务器总是被阻塞。
我用gdb调试,发现std::cout不行
调试上下文
Breakpoint 1, main () at shared_mem_server.cpp:35
35 sem_init(reinterpret_cast<sem_t*>(shm),0,1);
(gdb) p shm
= 0x7ffff7ff6000 ""
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 0 0
(gdb) s
__new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1) at sem_init.c:31
31 sem_init.c: No such file or directory.
(gdb) return
Make __new_sem_init return now? (y or n) n
Not confirmed
(gdb) finish
Run till exit from #0 __new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1)
at sem_init.c:31
main () at shared_mem_server.cpp:37
37 msgrcv(msgid,&msg,256,ret_type,0);
Value returned is = 0
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 1 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 0 0
(gdb) p sem_sz
= 32
(gdb) n
38 sem_p(reinterpret_cast<sem_t*>(shm));
(gdb) n
39 if(shm + sem_sz == "q")
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 3355185 0
(gdb) x/12w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 3355185 0 0 0
(gdb) n
41 std::cout << "shared memory " << shm + sem_sz;
(gdb) n
42 sem_v(reinterpret_cast<sem_t*>(shm));
(gdb) q
下面是代码
服务器代码:
#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include "error.h"
#include "sempv.h"
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
int main(){
key_t key;
int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
char *shm;
msg_form msg;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
unix_error("create shared memory error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
unix_error("msgget error");
sem_init(reinterpret_cast<sem_t*>(shm),0,1);
while(true){
msgrcv(msgid,&msg,256,ret_type,0);
sem_p(reinterpret_cast<sem_t*>(shm));
if(shm + sem_sz == "q")
break;
std::cout << "shared memory " << shm + sem_sz;
sem_v(reinterpret_cast<sem_t*>(shm));
}
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
shmctl(msgid,IPC_RMID,0);
return 0;
}
客户代码
#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include "error.h"
#include "sempv.h"
#include <string>
using std::string;
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
int main(){
key_t key;
int shmid,msgid,sem_sz = sizeof(sem_t);
char *shm;
int err;
msg_form msg;
string s;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,0)) == -1)
unix_error("shmget error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,0777)) == -1)
unix_error("msgget error");
std::cout << "key is " << key << std::endl;
while(getline(std::cin,s)){
sem_p(reinterpret_cast<sem_t*>(shm));
memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
memcpy(shm+sem_sz,s.c_str(),s.size());
msg.msg_type = 888;
sprintf(msg.msg_text,"shared memory write signal");
if((err = msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1)
unix_error("msgsnd error");
sem_v(reinterpret_cast<sem_t*>(shm));
//std::cout << "message send\n";
}
return 0;
}
一般备注:
System V IPC 已弃用,对于任何新项目,建议使用 POSIX 对应项 (man 7 shm_overview and man 7 mq_overview)
client/server 同步较弱:客户端可能会在服务器读取共享内存段时覆盖它。您应该使用互斥体 read/write 进入共享内存段(当一个 reading/writing 另一个被阻塞时):cf. man 7 sem_overview
由于您没有在服务器中进行任何清理,请确保在每次尝试之间删除 shell 下带有 ipcs/ipcrm 的队列和共享内存标识符申请
在服务器中:
- 错误检查是错误的:如果 shmget()/msgget return -1 并且 errno 等于 EEXIST,您继续但没有得到任何 shm/msg 标识符 - 1!
在客户端:
为了健壮性,最好使用 snprintf() 而不是 sprintf() 来强制检查缓冲区的边界
客户端不应将 IPC_CREAT 用于 msgget()。通常,服务器的角色是在 server/client 应用程序
中创建资源
这是您修改后的代码的 C 版本:
服务器:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
static void unix_error(const char *str)
{
fprintf(stderr, "%s\n", str);
exit(1);
}
int main(){
key_t key;
int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
char *shm;
struct msg_form msg;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
unix_error("create shared memory error");
if((shm = (char *)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memory error");
}
if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
unix_error("msgget error");
sem_init((sem_t *)(shm),1,1);
while(1){
msgrcv(msgid,&msg,256,ret_type,0);
sem_wait((sem_t *)(shm));
if (*(shm + sem_sz) == 'q' && *(shm + sem_sz + 1) == '\n') {
sem_post((sem_t *)(shm));
break;
}
printf("shared memory: %s", shm + sem_sz);
sem_post((sem_t *)(shm));
}
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
msgctl(msgid,IPC_RMID,0);
return 0;
}
客户:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
static void unix_error(const char *str)
{
fprintf(stderr, "%s\n", str);
exit(1);
}
int main(){
key_t key;
int shmid,msgid,sem_sz = sizeof(sem_t);
char *shm;
int err;
struct msg_form msg;
char s[256];
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,0)) == -1)
unix_error("shmget error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,0777)) == -1)
unix_error("msgget error");
printf("key is 0x%x\n", (int)key);
while(fgets(s, sizeof(s) - 1, stdin)) {
sem_wait((sem_t *)(shm));
memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
memcpy(shm+sem_sz,s, strlen(s));
msg.msg_type = 888;
snprintf(msg.msg_text, 256, "shared memory write signal");
if((err = msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1) {
sem_post((sem_t *)(shm));
unix_error("msgsnd error");
}
sem_post((sem_t *)(shm));
}
return 0;
}
客户端 readline 写入共享 memory.and 向服务器发送消息。 服务器获取消息并从共享内存中读取。
但是服务器无法正确输出, 服务器没有任何输出,不知道为什么。
手册页说: 如果没有可用的请求类型的消息并且未在 msgflg 中指定 IPC_NOWAIT,则调用进程将被阻塞,直到出现以下情况之一
但是服务器总是被阻塞。
我用gdb调试,发现std::cout不行
调试上下文
Breakpoint 1, main () at shared_mem_server.cpp:35
35 sem_init(reinterpret_cast<sem_t*>(shm),0,1);
(gdb) p shm
= 0x7ffff7ff6000 ""
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 0 0
(gdb) s
__new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1) at sem_init.c:31
31 sem_init.c: No such file or directory.
(gdb) return
Make __new_sem_init return now? (y or n) n
Not confirmed
(gdb) finish
Run till exit from #0 __new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1)
at sem_init.c:31
main () at shared_mem_server.cpp:37
37 msgrcv(msgid,&msg,256,ret_type,0);
Value returned is = 0
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 1 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 0 0
(gdb) p sem_sz
= 32
(gdb) n
38 sem_p(reinterpret_cast<sem_t*>(shm));
(gdb) n
39 if(shm + sem_sz == "q")
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 3355185 0
(gdb) x/12w 0x7ffff7ff6000
0x7ffff7ff6000: 0 0 0 0
0x7ffff7ff6010: 0 0 0 0
0x7ffff7ff6020: 3355185 0 0 0
(gdb) n
41 std::cout << "shared memory " << shm + sem_sz;
(gdb) n
42 sem_v(reinterpret_cast<sem_t*>(shm));
(gdb) q
下面是代码
服务器代码:
#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include "error.h"
#include "sempv.h"
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
int main(){
key_t key;
int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
char *shm;
msg_form msg;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
unix_error("create shared memory error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
unix_error("msgget error");
sem_init(reinterpret_cast<sem_t*>(shm),0,1);
while(true){
msgrcv(msgid,&msg,256,ret_type,0);
sem_p(reinterpret_cast<sem_t*>(shm));
if(shm + sem_sz == "q")
break;
std::cout << "shared memory " << shm + sem_sz;
sem_v(reinterpret_cast<sem_t*>(shm));
}
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
shmctl(msgid,IPC_RMID,0);
return 0;
}
客户代码
#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include "error.h"
#include "sempv.h"
#include <string>
using std::string;
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
int main(){
key_t key;
int shmid,msgid,sem_sz = sizeof(sem_t);
char *shm;
int err;
msg_form msg;
string s;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,0)) == -1)
unix_error("shmget error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,0777)) == -1)
unix_error("msgget error");
std::cout << "key is " << key << std::endl;
while(getline(std::cin,s)){
sem_p(reinterpret_cast<sem_t*>(shm));
memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
memcpy(shm+sem_sz,s.c_str(),s.size());
msg.msg_type = 888;
sprintf(msg.msg_text,"shared memory write signal");
if((err = msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1)
unix_error("msgsnd error");
sem_v(reinterpret_cast<sem_t*>(shm));
//std::cout << "message send\n";
}
return 0;
}
一般备注:
System V IPC 已弃用,对于任何新项目,建议使用 POSIX 对应项 (man 7 shm_overview and man 7 mq_overview)
client/server 同步较弱:客户端可能会在服务器读取共享内存段时覆盖它。您应该使用互斥体 read/write 进入共享内存段(当一个 reading/writing 另一个被阻塞时):cf. man 7 sem_overview
由于您没有在服务器中进行任何清理,请确保在每次尝试之间删除 shell 下带有 ipcs/ipcrm 的队列和共享内存标识符申请
在服务器中:
- 错误检查是错误的:如果 shmget()/msgget return -1 并且 errno 等于 EEXIST,您继续但没有得到任何 shm/msg 标识符 - 1!
在客户端:
为了健壮性,最好使用 snprintf() 而不是 sprintf() 来强制检查缓冲区的边界
客户端不应将 IPC_CREAT 用于 msgget()。通常,服务器的角色是在 server/client 应用程序
中创建资源
这是您修改后的代码的 C 版本:
服务器:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
static void unix_error(const char *str)
{
fprintf(stderr, "%s\n", str);
exit(1);
}
int main(){
key_t key;
int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
char *shm;
struct msg_form msg;
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
unix_error("create shared memory error");
if((shm = (char *)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memory error");
}
if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
unix_error("msgget error");
sem_init((sem_t *)(shm),1,1);
while(1){
msgrcv(msgid,&msg,256,ret_type,0);
sem_wait((sem_t *)(shm));
if (*(shm + sem_sz) == 'q' && *(shm + sem_sz + 1) == '\n') {
sem_post((sem_t *)(shm));
break;
}
printf("shared memory: %s", shm + sem_sz);
sem_post((sem_t *)(shm));
}
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
msgctl(msgid,IPC_RMID,0);
return 0;
}
客户:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
const int SHM_SIZE=1024;
struct msg_form{
long msg_type;
char msg_text[256];
};
static void unix_error(const char *str)
{
fprintf(stderr, "%s\n", str);
exit(1);
}
int main(){
key_t key;
int shmid,msgid,sem_sz = sizeof(sem_t);
char *shm;
int err;
struct msg_form msg;
char s[256];
if((key = ftok(".",'v')) < 0)
unix_error("ftok error");
if((shmid = shmget(key,SHM_SIZE,0)) == -1)
unix_error("shmget error");
if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
unix_error("attach shared memeory error");
}
if((msgid = msgget(key,0777)) == -1)
unix_error("msgget error");
printf("key is 0x%x\n", (int)key);
while(fgets(s, sizeof(s) - 1, stdin)) {
sem_wait((sem_t *)(shm));
memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
memcpy(shm+sem_sz,s, strlen(s));
msg.msg_type = 888;
snprintf(msg.msg_text, 256, "shared memory write signal");
if((err = msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1) {
sem_post((sem_t *)(shm));
unix_error("msgsnd error");
}
sem_post((sem_t *)(shm));
}
return 0;
}