【linux草鞋应用编程系列】_3_ 进程间通信
生活随笔
收集整理的這篇文章主要介紹了
【linux草鞋应用编程系列】_3_ 进程间通信
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、進程間通信
? ? ? ?linux下面提供了多種進程間通信的方法, 管道、信號、信號量、消息隊列、共享內存、套接字等。下面我們分別 介紹管道、信號量、消息隊列、共享內存。 ? ? ? ?信號和套接字在后續介紹。 ? 1、管道 ? ? 管道又分為無名管道、命名管道。 ? 無名管道用于父子進程間通信, 而命名管道則可以用于同一計算機上運行的 兩個進程間的通信。管道可以用類似“水管”的原理來理解。 ? 1)無名管道 ? ? 要在父子進程進程間使用管道進行通信,那么先需要創建管道, 在linux中使用 pipe()創建管道。其原型如下: PIPE(2) Linux Programmer’s Manual PIPE(2) NAMEpipe - create pipe SYNOPSIS#include <unistd.h>int pipe(int filedes[2]); //參數為一個長度為2 的整型數組的數組首地址, 為輸出參數, ? ? 返回值: ? ? ? ? ? ? ? ?成功創建管道返回0; 失敗則返回-1;? ? ?? ? ? 管道分為兩端,一端用來寫,另一端則用來讀(可以想象為水管,位置高的一端進水,位置低的一端將水流出去) 。 pipe()函數的輸出參數 filedes[0] 用于讀取數據, filedes[1] 用于寫入數據。 ? ??管道的操作和普通文件的操作一樣, 但是要注意,讀的時候要將寫端關閉,寫的時候要將讀端關閉。?? ? Exp: ?pipe.c ? 首先測試從父進程給子進程寫數據。 #include <stdio.h> #include <unistd.h> #include <stdlib.h>int main(int argc,char* argv[]) {int fd_pipe[2];pid_t pid;char buf[32];//創建管道if( pipe(fd_pipe) ){perror("create pipe");exit(1);}pid=fork();if( 0==pid ){/*close(fd_pipe[1]); //關閉寫端*/read(fd_pipe[0], buf,sizeof(buf));printf("in child process read data from pipe.\n");printf("the data read from pipe is:%s\n",buf);exit(0);}/*close(fd_pipe[0]); //關閉讀端*/write(fd_pipe[1], "pipe test",sizeof("pipe test"));sleep(1);return 0; } ? ? 程序執行情況如下: [root@localhost ipc]# gcc main.c [root@localhost ipc]# ./a.out in child process read data from pipe. the data read from pipe is:pipe test ? ? 利用系統調用 read()、write()進行操作的時候管道默認是阻塞的,如果管道沒有數據可讀,那么read( )函數就 阻塞,直到有數據讀才返回。 ? ?Exp: ?pipe.c ?子進程寫入數據到管道,父進程從管道讀取數據 #include <stdio.h> #include <unistd.h> #include <stdlib.h>#define CHAR "pipe test from child to parent\n"int main(int argc,char* argv[]) {int fd_pipe[2];pid_t pid;char buf[32];//創建管道if( pipe(fd_pipe) ){perror("create pipe");exit(1);}pid=fork();if( 0==pid ){close(fd_pipe[0]);write(fd_pipe[1],CHAR,sizeof(CHAR));exit(0);} close(fd_pipe[1]);read(fd_pipe[0],buf,sizeof(buf));printf("data from child is: %s",buf);return 0; } ? ? 執行結果如下: [root@localhost ipc]# gcc main.c [root@localhost ipc]# ./a.out data from child is: pipe test from child to parent 2)命名管道 ? ? 命名管道用于系統中兩個進程之間通信;命名管道可用于系統中兩個沒有親緣關系的進程進行通信(也可以用于父 子進程間的通信) 。 ? ? 要使用命名管道,則需要創建命名管道,用函數 mkfifo () 創建命名管道。其原型如下: MKFIFO(3) Linux Programmer’s Manual MKFIFO(3) NAMEmkfifo - make a FIFO special file (a named pipe) SYNOPSIS#include <sys/types.h>#include <sys/stat.h>int mkfifo( const char *pathname, //生成的管道特殊文件的位置和文件名mode_t mode); //管道特殊文件的訪問權限 返回值:???? ? ? ? ?成功創建管道文件返回0, 失敗返回 -1. ? ?? ? ??創建號管道特殊文件后,就可以和訪問普通文件一樣訪問管道特殊文件。 ? Exp: ?測試命名管道 ? ?pipe-w.c ?創建命令管道并向管道寫入數據 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h>#define CHAR "pipe named\n"int main(int argc,char* argv[]) {int fd;int ret;//創建管道ret=mkfifo("./fifo-pipe",0666);if(ret){perror("mkfifo: fifo-pipe");exit(0);}fd=open("./fifo-pipe",O_WRONLY);write(fd,CHAR,sizeof(CHAR));close(fd);return 0; } ? ? pipe-r.c 打開pipe-w.c 文件,并且從命名管道讀取數據: #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h>int main(int argc,char* argv[]) {int fd;int ret;char buf[32];//打開命名管道文件fd=open("./fifo-pipe",O_RDONLY);if(-1 == fd){perror("open fifo-pipe");exit(1);}ret=read(fd,buf,sizeof(buf));if(ret<0){perror("read fifo-pipe");exit(1);}printf("the data read from fifo pipe:%s\n",buf);close(fd);return 0; } 程序的執行結果如下: ? ??pipe-w.c 生成wp , ?pipe-r.c 生成rp [root@localhost pipe]# ll //查看沒有 fifo-pipe 的命名管道文件 總計 28 -rw-r--r-- 1 root root 560 12-11 16:57 pipe_fork.c -rw-r--r-- 1 root root 500 12-11 17:15 pipe-r.c -rw-r--r-- 1 root root 405 12-11 17:17 pipe-w.c -rwxr-xr-x 1 root root 5359 12-11 17:15 rp -rwxr-xr-x 1 root root 5296 12-11 17:17 wp [root@localhost pipe]# ./wp & //wp運行,并且進入后臺 [1] 29409 [root@localhost pipe]# jobs [1]+ Running ./wp & //wp在后臺運行, 等待命名管道的數據被讀取, 即wp 阻塞 [root@localhost pipe]# ./rp //rp 讀取管道數據, the data read from fifo pipe:pipe named //數據讀取成功 [1]+ Done ./wp //管道中的數據被讀取完后,wp不再阻塞,返回 [root@localhost pipe]# jobs [root@localhost pipe]# ll 總計 28 prw-r--r-- 1 root root 0 12-11 17:23 fifo-pipe //生成一個命名管道文件 -rw-r--r-- 1 root root 560 12-11 16:57 pipe_fork.c -rw-r--r-- 1 root root 500 12-11 17:15 pipe-r.c -rw-r--r-- 1 root root 405 12-11 17:17 pipe-w.c -rwxr-xr-x 1 root root 5359 12-11 17:15 rp -rwxr-xr-x 1 root root 5296 12-11 17:17 wp [root@localhost pipe]# ? ? 要點: ? ? ? ? ? ? 在進程操作管道的時候, write 和 read 都是阻塞的; 如果寫的數據沒有被讀取走,那么就會寫的進程就會 在 write 函數阻塞; ?如果讀數據的時候,管道沒有數據,那么就會等待管道里面別寫入數據,進程在read 函數阻塞。 ? ? 2、消息隊列 ? ? 消息隊列也是linux下進程間通信的一種方式, 如果要使用消息隊列在進程間進行通信,必須創建一個消息隊列 或者打開一個已經存在的消息隊列。 ? ? 要打開一個已經存在的消息隊列,或者創建一個新的消息隊列,則必須先獲取一個關于消息隊列的IPC鍵值;通過函 數 ftok( )獲取消息隊列的IPC鍵值。 ? ? ftok 的原型如下: FTOK(3) Linux Programmer’s Manual FTOK(3) NAMEftok - convert a pathname and a project identifier to a System V IPC key//由一個特定的工程號和文件生成一個特定的IPC鍵值, SYNOPSIS# include <sys/types.h># include <sys/ipc.h>key_t ftok(const char *pathname, //文件名int proj_id); //工程號 返回值: ? ? ? ? ? ? 成功返回 IPC鍵值, 失敗返回-1. ? ? 要點: ? ? ? ? ? ? 如果文件名和工程號一致,內核保證在任何進程中都將得到同樣的 IPC 鍵值。 ? ? ? 有了消息隊列的IPC鍵值后,就是創建或者打開消息隊列, 通過 msgget( ) 創建或打開一個消息隊列, 其原型如下: MSGGET(2) Linux Programmer’s Manual MSGGET(2) NAMEmsgget - get a message queue identifierSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget( key_t key, //IPC 鍵值int msgflg); //打開或者創建標志, 可以取值 IPC_CREAT ? ? 返回值: ? ? ? ? ? ? 如果成功,返回消息隊列的ID號, 失敗返回 -1。 ? ? ? 創建了消息隊列或者打開已經消息隊列后,就需要完消息隊列中添加消息,即發送消息; 發送消息通過函數 msgsnd( ) 實現。 ? ? 當發送完消息后,就可以從消息隊列中獲取消息,從消息隊列中讀取消息用函數 msgrcv( )實現。 ????原型如下: MSGOP(2) Linux Programmer’s Manual MSGOP(2) NAMEmsgop - message operations SYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgsnd(int msqid, //消息隊列IDconst void *msgp, //要發送的消息的消息結構體size_t msgsz, //消息字符串的大小,或者消息結構的大小int msgflg); // 消息標志 ssize_t msgrcv(int msqid, //消息隊列IDvoid *msgp, //接受消息的消息結構體指針size_t msgsz, //消息結構體的大小long msgtyp, //指定要接收到消息的類型int msgflg); //消息標志 要發送或接收消息,還需要定義一個如下格式的結構體:struct msgbuf {long mtype; /* message type, must be > 0 */ //消息類型, 這個值必須大于 0char mtext[1]; /* message data */ //要發送的消息數據, 字符數組長度可以根據實際需要定義 }; ? ? 消息隊列使用完后,需要刪除消息隊列,通過 msgctl 函數實現,這是一個與ioctl 函數類似的函數,其原型如下: MSGCTL(2) Linux Programmer’s Manual MSGCTL(2) NAMEmsgctl - message control operations SYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgctl(int msqid, //消息隊列IDint cmd, //操作命令, 操作命令有很多,刪除消息隊列用 IPC_RMID 命令struct msqid_ds *buf); //輸出參數,通過這個結構體可獲取消息隊列的狀態信息,如果不需要獲取//消息隊列的信息,那么就設置為NULL ? ? 返回值:? ? ? ? ? ? ? ? ? 成功刪除(cmd=IPC_RMID)返回0 ,失敗返回-1. ? Exp: 發送消息的源文件: ?msgsnd.c ? #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h>typedef struct {long type;char data[128]; }msgbuf;int main(void) {int ret;key_t key;int msgid;msgbuf msg={type: 1,data: "this is a message queue test.\n",};//獲取鍵值key=ftok("./msgsnd.c",1);if(-1 == key){perror("ftok");exit(1);}//打開或創建一個消息隊列msgid=msgget(key,IPC_CREAT);if(-1 == msgid ){perror("msgget");exit(2);}//發送消息ret=msgsnd(msgid,&msg,sizeof(msgbuf),0);if(-1 == ret){perror("msgsnd");}return 0; } ? ? 接收消息的源代碼文件: ?msgrcv.c #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h>typedef struct {long type;char data[128]; }msgbuf;int main(int argc,char* argv[]) {int ret;key_t key;int msgid;msgbuf msg;//獲取鍵值key=ftok("./msgsnd.c",1);if(-1 == key ){perror("ftok");exit(1);}//打開消息隊列msgid=msgget(key,0);if(-1 == msgid ){perror("msgget");exit(2);}//接收消息ret=msgrcv(msgid, &msg, sizeof(msgbuf),1,0);if(-1 == ret){perror("msgrcv");exit(3);}printf("the recive message is: %s",msg.data);//刪除消息隊列 msgctl(msgid,IPC_RMID,NULL);return 0; }? 測試結果如下: [root@localhost msg]# gcc msgsnd.c -o snd [root@localhost msg]# gcc msgrcv.c -o rcv [root@localhost msg]# ./snd [root@localhost msg]# ./rcv the recive message is: this is a message queue test. [root@localhost msg]#?
3、信號量 ? ? 信號量主要用于兩個進程間同步的,一般用于多進程間的同步操作。 ? ? 例如當兩個進程同時要訪問聲卡的時候,那么就需要控制聲卡先由那個進程操作,等第一個進程操作完后,其他進程 才能進行操作; 但是為什么我們可以同時用mplayer 還能同時使用kmplyer播放音樂呢? 從用戶的角度來看,確實是這 樣的,但是從硬件的角度來看,在某一時刻聲卡就只能為一個應用層程序服務,當兩個應用程序同時對聲卡進行操作時就 會出現異常,為了防止這種異常,需要進行對兩個進程進行控制,當有一個進程獲取聲卡的控制權后,另外的一個進程就 不能在同一時刻訪問聲卡,這就是互斥操作。(可以這樣測試, 在windows的操作系統上安裝VM虛擬機,打開windows media player, 然后啟動虛擬機(設置虛擬機在啟動的時候自動掛載聲卡設備),這時候聲卡就會工作不正常,會出現 一小段時間的異常, 聲音不正常,這就是出現兩個應用程序同時使用聲卡出現的異常)。 ? ??信號量就是為解決類似的問題而設計的,信號量用來控制應用程序在同一時刻對某一系統資源的訪問(這個系統資源 也稱作臨界資源,訪問臨界資源的代碼,也稱作臨界區代碼)。 ? ? 信號量用結構體 struct sembuf 描述,其定義如下: /* semop system calls takes an array of these. */ struct sembuf {unsigned short sem_num; /* semaphore index in array */ //信號量集合中的信號量索引值,即表示信號量集合中第幾個信號量short sem_op; /* semaphore operation */ //要對信號量進行的操作,=-1 表示信號量不可獲取, =1 表示可以獲取信號量short sem_flg; /* operation flags */ //信號量標志 }; ? ? 這里有一點需要說明: ?通常對信號量進行操作分為 P操作、V操作,當設置 sem_op = -1 時表示進行P操作, sem_op = 1 時表示要進行V操作。 ? ? ? 和消息隊列一樣,要使用信號量,首先需要獲取一個用于信號量到IPC鍵值, 用 ftok( ) 函數獲取。 獲取到用于 信號量到IPC鍵值后,還需要創建或者打開一個已經存在的信號量,通過打開或創建信號量獲取一個關于信號量的 信號量ID;然后通過對信號量ID進行操作,就可以使用信號量。 ? ? 通過semget()函數創建或打開一個信號量,并獲取關于信號量的ID; 原型如下: SEMGET(2) Linux Programmer’s Manual SEMGET(2) NAMEsemget - get a semaphore set identifier //獲取一個信號集合的ID SYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget( key_t key, //IPC鍵值int nsems, //信號量集合中信號量的個數, 要創建的信號量到個數int semflg); //信號量的標志, 同OPEN的打開標志類似 ? ??? 在獲取信號量集合ID后,需要對信號量進行一些設定(或者說信號量初始化),然后才能操作,通過函數 semctl( )對 信號量進行初始化操作; setctl( )的原型如下: SEMCTL(2) Linux Programmer’s Manual SEMCTL(2) NAMEsemctl - semaphore control operationsSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(int semid, //信號量集合ID int semnum, //信號量集合中的信號量索引值int cmd, //要對信號量進行的操作,可以使用的命名: IPC_SET、IPC_STAT、IPC_INFO、GETVAL、SETVAL.........); //最后一個參數根據 操作的不同,可以傳遞,也可以不傳遞 ? ? 返回值: ? ? ? ? ? ? 如果成功返回0 ,失敗返回-1.(操作為 IPC_GETVAL, 成功返回信號量到值 )。 ? ? SETVAL: 對信號量進行設置。 這時候,要傳遞4個參數, 最后一個可變參數,要定義一個類型如下: union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux specific) */}; ? ? 這是一個聯合體類型,根據不同的操作命令,傳遞的值表示不同的意義。 ? ????可以通過 semop( )函數來操作信號量,其原型如下: SEMOP(2) Linux Programmer’s Manual SEMOP(2)NAMEsemop, semtimedop - semaphore operationsSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semop(int semid, //信號量集合IDstruct sembuf *sops, //信號量結構體指針unsigned nsops); //表示要操作的信號量個數int semtimedop(int semid, //信號量集合IDstruct sembuf *sops, //信號量結構體指針unsigned nsops, //表示要操作的信號量個數struct timespec *timeout); //表示超時等待時間,如果在超時時間內沒有獲取到可操作的信號量,就返回 Exp: ?測試 信號量到代碼, #include <stdio.h> #include <sys/ipc.h> #include <sys/sem.h> #include <fcntl.h> #include <stdlib.h>int main(void) {int i;int j;int ret;int fd; pid_t pid;key_t key;int semid;char buf[64];int size;struct sembuf sembuf;/*sembuf=(struct sembuf*)malloc(sizeof (struct sembuf));*///打開文件,用來進行操作fd=open("./test",O_RDWR | O_CREAT | O_TRUNC,0666);if(-1 == fd){perror("open");exit(1);}//IPC鍵值key=ftok("./main.c",1);if(-1 == key){perror("ftok");exit(2);}//獲取信號量集合的IDsemid=semget(key,1,IPC_CREAT);if(-1 == semid ){perror("semget");exit(3);}//初始化信號量集合中的第一個信號量,設定信號量的值為0 , sem.sem_op = 0;ret=semctl(semid, 0, SETVAL, 1);pid=fork();if( pid==0 ) //----------------子進程------------ {//信號量的P 操作, 即加鎖信號量sembuf.sem_num=0;sembuf.sem_op=-1;sembuf.sem_flg=0;semop(semid,&sembuf,1);size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());for(i=0;i<5;i++){j=0;while(j<size){ret=write(fd,&buf[j++], 1);if(-1 == ret){perror("write");exit(4);}usleep(1);}}//信號量的V操作,即解鎖信號量sembuf.sem_num=0;sembuf.sem_op=1;sembuf.sem_flg=0;semop(semid,&sembuf,1);exit(0);}//---------------子進程結束---------------------//-----------------------父進程---------------//信號量的P 操作, 即加鎖信號量sembuf.sem_num=0;sembuf.sem_op=-1;sembuf.sem_flg=0;semop(semid,&sembuf,1);size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());for(i=0;i<5;i++){j=0;while(j<size){ret=write(fd,&buf[j++], 1);if(-1 == ret){perror("write");exit(4);}usleep(1);}}//信號量的V操作,即解鎖信號量sembuf.sem_num=0;sembuf.sem_op=1;sembuf.sem_flg=0;semop(semid,&sembuf,1);semctl(semid,0,IPC_RMID);close(fd);return 0; } 代碼執行后生成的test文件內容如下: pid=1114, ppid=714 pid=1114, ppid=714 pid=1114, ppid=714 pid=1114, ppid=714 pid=1114, ppid=714 pid=1115, ppid=1 pid=1115, ppid=1 pid=1115, ppid=1 pid=1115, ppid=1 pid=1115, ppid=1 如果將信號量的加鎖和解鎖取消, 代碼如下: #include <stdio.h> #include <sys/ipc.h> #include <sys/sem.h> #include <fcntl.h> #include <stdlib.h>int main(void) {int i;int j;int ret;int fd; pid_t pid;key_t key;int semid;char buf[64];int size;struct sembuf sembuf;/*sembuf=(struct sembuf*)malloc(sizeof (struct sembuf));*///打開文件,用來進行操作fd=open("./test",O_RDWR | O_CREAT | O_TRUNC,0666);if(-1 == fd){perror("open");exit(1);}//IPC鍵值key=ftok("./main.c",1);if(-1 == key){perror("ftok");exit(2);}//獲取信號量集合的IDsemid=semget(key,1,IPC_CREAT);if(-1 == semid ){perror("semget");exit(3);}//初始化信號量集合中的第一個信號量,設定信號量的值為0 ret=semctl(semid, 0, SETVAL, 1);pid=fork();if( pid==0 ) //----------------子進程------------ {//信號量的P 操作, 即加鎖信號量sembuf.sem_num=0;sembuf.sem_op=-1;sembuf.sem_flg=0;/*semop(semid,&sembuf,1);*/ //取消信號量到作用 size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());for(i=0;i<5;i++){j=0;while(j<size){ret=write(fd,&buf[j++], 1);if(-1 == ret){perror("write");exit(4);}usleep(1);}}//信號量的V操作,即解鎖信號量sembuf.sem_num=0;sembuf.sem_op=1;sembuf.sem_flg=0;/*semop(semid,&sembuf,1);*/ //取消信號量到作用 exit(0);}//---------------子進程結束---------------------//-----------------------父進程---------------//信號量的P 操作, 即加鎖信號量sembuf.sem_num=0;sembuf.sem_op=-1;sembuf.sem_flg=0;/*semop(semid,&sembuf,1);*/ //取消信號量到作用 size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());for(i=0;i<5;i++){j=0;while(j<size){ret=write(fd,&buf[j++], 1);if(-1 == ret){perror("write");exit(4);}usleep(1);}}//信號量的V操作,即解鎖信號量sembuf.sem_num=0;sembuf.sem_op=1;sembuf.sem_flg=0;/*semop(semid,&sembuf,1);*/ //取消信號量到作用 semctl(semid,0,IPC_RMID);close(fd);return 0; } ? ? 生成的test文件內容如下: ppiidd==22333387,, ppppiidd==2731347ppiidd==22333378,, ppppiidd==721343 7p ipdi=d2=323373,8 ,p ppipdi=d7=1243 3p7i dp=i2d3=3273,3 8p,p ipdp=i7d1=42 3p3i7d =p2i3d3=72,3 3p8p,i dp=p7i1d4= 2337 ? ? 可以發現兩個進程同時訪問一個文件,而沒有互斥機制的話,就會出現亂碼。因此在訪問臨界資源的時候,就需要 采用互斥機制。 ? ? 4、共享內存 ? ? 進程都具有自己的虛擬地址空間(即進程空間),進程A不能隨意的訪問進程B的進程空間; 內核提供了一種機制, 可以在物理內存中開辟一塊存儲空間,這塊存儲空間可供進程A或者進程B訪問, 這樣一塊存儲空間就是共享內存。 ? ? 要使用共享內存也需要獲取一個IPC鍵值,通過 ?ftok()獲取IPC鍵值。 ? ? 獲取到IPC鍵值后,就需要向系統申請共享的存儲空間,通過函數 shmget( ) 申請共享空間,并獲取關于共享內存的 ID標識符。 shmget()的原型如下所示: SHMGET(2) Linux Programmer’s Manual SHMGET(2) NAMEshmget - allocates a shared memory segment SYNOPSIS#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, //IPC 鍵值size_t size, //要申請的內存空間的大小int shmflg); //共享內存的空間打開標志 ,與 open 的打開標志類似, 返回值:申請成功返回共享內存標識ID, 失敗返回-1。 ? ? 申請成功后,還不能訪問共享內存,因為訪問內存需要知道內存的地址或者指針,所以就需要向系統申請返回 共享內存的地址或者指針。通過 shmmat( )向系統申請返回共享內存的首地址或者指針。其原型如下: SHMOP(2) Linux Programmer’s Manual SHMOP(2) NAMEshmop - shared memory operations SYNOPSIS#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, //共享內存標志IDconst void *shmaddr, //傳遞NULL,表示要系統分配存儲緩沖區,傳遞地址表示指定地址int shmflg); //打開標志,int shmdt(const void *shmaddr); //刪除共享內存 返回值: ? ? ? ? 成功返回共享內存的首地址(虛擬地址),失敗返回NULL。 ? ? ? ? ? 在成功返回共享內存首地址后,就可以向訪問用malloc 分配的內存一樣進行操作。 ? Exp: ?申請共享內存,并往共享內存寫的文件 ?shm-w.c? #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <string.h>#define SHM_SIZE 128int main(int argc,char* argv[]) {key_t key;int shm_id;char* shm_p;//獲取IPC 鍵值key=ftok("./shm-w.c",1);if(-1 == key){perror("ftok");exit(1);}//申請共享內存空間,大小為 SHM_SIZEshm_id=shmget(key,SHM_SIZE,IPC_CREAT);if(-1 == shm_id ){perror("shmget");exit(2);}//將申請的共享內存映射到用戶空間shm_p=shmat(shm_id,NULL,0); // if(NULL == shm_p ){perror("shmat");exit(3);}//將數據寫入到共享內存 寫入到數據可以在其他進程中讀取memset(shm_p,0,SHM_SIZE);strcpy(shm_p, "this is a sheard memmory.\n"); //這個函數不安全,需要注意return 0; }從共享內存中讀取數據的文件 shm-r.c #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <string.h>#define SHM_SIZE 128int main(int argc,char* argv[]) {key_t key;int shm_id;char* shm_p;char buf[SHM_SIZE];//獲取IPC 鍵值key=ftok("./shm-w.c",1);if(-1 == key){perror("ftok");exit(1);}//申請共享內存空間,大小為 SHM_SIZEshm_id=shmget(key,SHM_SIZE,IPC_CREAT);if(-1 == shm_id ){perror("shmget");exit(2);}//將申請的共享內存映射到用戶空間shm_p=shmat(shm_id,NULL,0); // if(NULL == shm_p ){perror("shmat");exit(3);}//從共享內存讀取數據memset(buf,0,SHM_SIZE);strcpy(buf, shm_p); //這個函數不安全,需要注意printf("the data read from sheard memory is: %s",buf);shmdt(shm_p); //申請撤銷共享內存return 0; } 程序執行的效果如下: [root@localhost shm]# gcc shm-w.c -o shmw [root@localhost shm]# gcc shm-r.c -o shmr [root@localhost shm]# ./shmw [root@localhost shm]# ./shmr the data read from sheard memory is: this is a sheard memmory. [root@localhost shm]#?
【Linux草鞋應用編程系列】_3_進程間通信
本系列文章未完,待續。
如果查看的過程中發現錯誤,請不吝指教,包括錯別字、標點符號等。
? ?前篇:【linux草鞋應用編程系列】_2_ 環境變量和進程控制?
?轉載于:https://www.cnblogs.com/volcanol/p/3473642.html
總結
以上是生活随笔為你收集整理的【linux草鞋应用编程系列】_3_ 进程间通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sharepoint权限操作(记录以备忘
- 下一篇: S5PV210之Sate210-F DI