1、安装多进程通信库boost:
boost中,用到了别的函数库,所以为了使用boost中相应的功能,需要先安装系统中可能缺失的库
apt-get install mpi-default-dev #安装mpi库
apt-get install libicu-dev #支持正则表达式的UNICODE字符集
apt-get install python-dev #需要python的话
apt-get install libbz2-dev #如果编译出现错误:bzlib.h: No such file or directory
上述函数库装好之后,就可以编译boost库了。解压boost_1_64_0.tar.bz2,得到/boost_1_64_0,将当前工作目录切换到此文件夹下。
./bootstrap.sh
生成bjam,上述命令可以带有各种选项,具体可参考帮助文档: ./bootstrap.sh --help。其中--prefix参数,可以指定安装路径,如果不带--prefix参数的话(推荐),默认路径是 /usr/local/include 和 /usr/local/lib,分别存放头文件和各种库。执行完成后,会生成bjam,已经存在的脚本将会被自动备份。注意,boost 1. 64会在当前目录下,生成两个文件bjam和b2,这两个是一样的,所以接下来的步骤,可以用这两个中的任意一个来执行。
using mpi ; #如果需要MPI功能,需要在 /tools/build/v2/user-config.jam 文件的末尾添加
接下来就是利用生成的bjam脚本编译源代码了
./b2 -a -sHAVE_ICU=1 #-a参数,代表重新编译,-sHAVE_ICU=1代表支持Unicode/ICU
编译完成后,进行安装,也就是将头文件和生成的库,放到指定的路径(--prefix)下
./b2 install
至此,如果一切顺利,就完成安装了。(此部分引用于网络,出处不记得了,有相关版权问题请留言)
2. 消息机制
消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息。消息队列存在于系统内核中,消息的数量受系统限制。通过命令ipcs -q进行查看。
//Msgsend.cpp:
#include
#include
#include
#include
#include
#include
#define MAX_TEXT 512
struct msg_st {
int destAddr;
int sourceAddr;
char text[MAX_TEXT];
};
int main() {
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
//建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
//向消息队列中写消息,直到写入end
while(running) {
//输入数据
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
data.destAddr = 56; //注意2
data.sourceAddr = 58;
strcpy(data.text, buffer);
//向队列发送数据
if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(msgrcv(msgid, (void*)&data, BUFSIZ, 58, 0) == -1){
fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s\n",data.text);
//输入end结束输入
if(strncmp(buffer, "end", 3) == 0)
running = 0;
sleep(1);
}
exit(EXIT_SUCCESS);
}
//Msgreceive.cpp:
#include
#include
#include
#include
#include
#include
#define MAX_TEXT 512
struct msg_st {
int destAddr;
int sourceAddr;
char text[BUFSIZ];
};
int main() {
int running = 1;
int msgid = -1;
struct msg_st data;
long int msgtype = 0; //注意1
char buffer[32] = {'a','s','r','k'};
//建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("BUFSIZ = %d\r\n",BUFSIZ);
//从队列中获取消息,直到遇到end消息为止
while(running) {
if(msgrcv(msgid, (void*)&data, BUFSIZ, 56, 0) == -1) {
fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s\n",data.text);
data.destAddr = 58;
data.sourceAddr = 56;
strcpy(data.text, buffer);
if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1){
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
//遇到end结束
if(strncmp(data.text, "end", 3) == 0)
running = 0;
}
//删除消息队列
if(msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
以上例子,实测可用,修改为自己需要的函数体即可。
3. 共享内存及内存映射
mmap和shm共享内存的区别和联系
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。 成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。
mmap和shm的机制
mmap的机制:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。
shm的机制:每个进程的共享内存都直接映射到实际物理存储器里面。
区别:
1、mmap保存到实际硬盘,实际存储并没有反映到主存上。
优点:储存量可以很大(多于主存);缺点:进程间读取和写入速度要比主存的要慢。
2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。
优点:进程间访问速度(读写)比磁盘要快;缺点:储存量不能非常大(多于主存)
在使用时,如果分配的存储量不大,那么使用shm;如果存储量大,那么使用mmap。
mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了。简单说就是把一个文件的内容在内存里面做一个映像,内存比磁盘快些。基本上它是把一个档案对应到你的virtual memory 中的一段,并传回一个指针。
//创建文件映射
#include
#include
#include
#include
#include
int main(int argc, char* argv[ ])
{
using namespace boost::interprocess;
try {
// creating our first shared memory object.
shared_memory_object sharedmem1(create_only, "multishm", read_write);
// setting the size of the shared memory
sharedmem1.truncate(256);
// map the shared memory to current process
mapped_region mmap(sharedmem1,read_write);
// access the mapped region using get_address
std::strcpy(static_cast(mmap.get_address()), "you are the best!\n");
} catch (interprocess_exception& e) {
// .. . clean up
}
}
//读取文件映射后的共享内存
#include
#include
#include
#include
#include
int main(int argc, char *argv[ ])
{
using namespace boost::interprocess;
try {
// opening an existing shared memory object
shared_memory_object sharedmem2(open_only, "multishm", read_only);
// map shared memory object in current address space
mapped_region mmap(sharedmem2, read_only);
// need to type-cast since get_address returns void*
char *str1 = static_cast (mmap.get_address());
printf("shm access ok\r\n");
printf("sharememory str=%s\r\n",str1);
shared_memory_object::remove("multishm");
} catch (interprocess_exception& e) {
}
return 0;
}
共享内存示例
//Servershm.c
#include
#include
#include
#include
#include
#include
#define SEMID 67865678
#define SHMID 13566876
int semid;
int shmid;
struct People{
char name[10];
int age;
};
/*信号量的P操作*/
void SemphoreP(){
struct sembuf sem_p;
sem_p.sem_num=0;/*设置哪个信号量*/
sem_p.sem_op=-1;/*定义操作*/
if(semop(semid,&sem_p,1)==-1)
printf("p operation is fail\n");
}
/*信号量的V操作*/
void SemphoreV(){
struct sembuf sem_v;
sem_v.sem_num=0;
sem_v.sem_op=1;
if(semop(semid,&sem_v,1)==-1)
printf("v operation is fail\n");
}
int main(){
/*创建信号量的XSI IPC*/
semid=semget(SEMID,1,0666|IPC_CREAT);//参数nsems,此时为中间值1,指定信号灯集包含信号灯的数目
if(semid==-1){
printf("creat sem is fail\n");
}
//创建共享内存
shmid=shmget(SHMID,1024,0666|IPC_CREAT);//对共享内存
if(shmid==-1){
printf("creat shm is fail\n");
}
/*设置信号量的初始值,就是资源个数*/
union semun{
int val;
struct semid_ds *buf;
unsigned short*array;
}sem_u;
sem_u.val=1;/*设置变量值*/
semctl(semid,0,SETVAL,sem_u);//初始化信号量,设置第0个信号量,p()操作为非阻塞的
struct People*addr;
addr=(struct People*)shmat(shmid,0,0);//将共享内存映射到调用此函数的内存段
if(addr==(struct People*)-1){
printf("shm shmat is fail\n");
}
/*向共享内存写入数据*/
SemphoreP();
strcpy((*addr).name,"xiaoming");
(*addr).age=10;
SemphoreV();
/*将共享内存与当前进程断开*/
if(shmdt(addr)==-1){
printf("shmdt is fail\n");
}
}
//Clientshm.c
#include
#include
#include
#include
#include
#include
#define SEMID 67865678
#define SHMID 13566876
int semid;
int shmid;
void SemphoreP(){
struct sembuf sem_p;
sem_p.sem_num=0;
sem_p.sem_op=-1;
if(semop(semid,&sem_p,1)==-1){
printf("p operation is fail\n");
}
}
/*信号量的V操作*/
void SemphoreV(){
struct sembuf sem_v;
sem_v.sem_num=0;
sem_v.sem_op=1;
if(semop(semid,&sem_v,1)==-1){
printf("v operation is fail\n");
}
}
int main(){
struct People{
char name[10];
int age;
};
/*读取共享内存和信号量的IPC*/
semid=semget(SEMID,0,0666);
if(semid==-1){
printf("creat sem is fail\n");
}
shmid=shmget(SHMID,0,0666);
if(shmid==-1){
printf("creat shm is fail\n");
}
/*将共享内存映射到当前进程的地址中,对共享内存操作*/
struct People*addr;
addr=(struct People*)shmat(shmid,0,0);
if(addr==(struct People*)-1){
printf("shm shmat is fail\n");
}
while(1){
/*从共享内存读出数据*/
SemphoreP();
printf("name:%s\n",addr->name);
printf("age:%d\n",addr->age);
SemphoreV();
usleep(2000000);
}
/*将共享内存与当前进程断开*/
if(shmdt(addr)==-1){
printf("shmdt is fail\n");
}
/*IPC必须显示删除。否则会一直留存在系统中*/
if(semctl(semid,0,IPC_RMID,0)==-1){
printf("semctl delete error\n");
}
if(shmctl(shmid,IPC_RMID,NULL)==-1){
printf("shmctl delete error\n");
}
}
以上示例均实测可用,修改后可加入工程或作为独立模块调试使用。