-
信號(hào)
- 信號(hào)是linux操作系統(tǒng)進(jìn)程間通信的一種方式骡楼,一個(gè)應(yīng)用進(jìn)程可以接受、發(fā)送信號(hào)給另一個(gè)進(jìn)程稽鞭,當(dāng)進(jìn)程捕獲到某個(gè)信號(hào)時(shí)鸟整,可以執(zhí)行某些特定的動(dòng)作。
-
與信號(hào)操作有關(guān)的函數(shù)位于signal.h頭文件中朦蕴,一個(gè)重要的函數(shù)聲明如下
該函數(shù)設(shè)置sig表示的信號(hào)由func表示的函數(shù)來(lái)處理篮条,返回一個(gè)與func同類(lèi)型的函數(shù)弟头,或以下兩個(gè)信號(hào)之一
- 一個(gè)簡(jiǎn)單的例子
#include<stdio.h> #include<signal.h> #include<stdlib.h> #include<unistd.h> void ouch(int sig){ printf("Oh, I got signal %d\n", sig); (void) signal(SIGINT, SIG_DFL); } int main(){ (void) signal(SIGINT, ouch); while(1){ printf("hello world!\n"); sleep(1); } }
-
可以使用kill函數(shù)向指定進(jìn)程發(fā)送信號(hào)
看一個(gè)簡(jiǎn)單的例子
#include<stdio.h> #include<stdlib.h> #include<signal.h> #include<sys/types.h> #include<unistd.h> static int alarm_handled = 0; void ding(int sig){ alarm_handled = 1; } int main(){ printf("process %d starting...\n", getpid()); (void) signal(SIGALRM, ding); switch(fork()){ case -1: perror("create process failed!"); break; case 0: sleep(2); kill(getppid(), SIGALRM); exit(0); break; } printf("waiting for SIGALRM...\n"); pause(); if(alarm_handled){ printf("catched the alarm sig!\n"); } return 0; }
-
使用更加健壯的signal接口,sigaction
使用sigaction改寫(xiě)第一個(gè)例子
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> #include<signal.h> void ouch(int sig){ printf("Oh, I got sig %d\n", sig); (void)signal(SIGINT, SIG_DFL); } int main(){ struct sigaction act; act.sa_handler = ouch; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, 0); while(1){ printf("Hello world!\n"); sleep(1); } return 0; }
-
還需要了解一些操作sigset_t的一些函數(shù)
-
管道-pipe
管道是應(yīng)用進(jìn)程之間的單向數(shù)據(jù)通道涉茧,進(jìn)程可以通過(guò)管道發(fā)送數(shù)據(jù)給另一個(gè)進(jìn)程赴恨,通過(guò)popen系統(tǒng)調(diào)用,可以打開(kāi)一個(gè)連接某個(gè)程序的管道伴栓,可以是r伦连,也可以是w
一個(gè)讀取信息的例子
#include<stdio.h> #include<stdlib.h> int main(){ char info[50]; FILE* fp = popen("uname -a", "r"); if(fp == NULL){ perror("create pipe to uname failed!"); exit(0); } int num = fread(info, sizeof(char), 50, fp); printf("got information: - \n%s\n", info); return 0; }
一個(gè)寫(xiě)數(shù)據(jù)的例子
#include<stdio.h> #include<stdlib.h> #include<string.h> int main(){ FILE* fp_write = popen("od -c", "w"); char info[50]; sprintf(info, "once upon a time, there was ..."); if(fp_write != NULL){ fwrite(info, sizeof(char), strlen(info), fp_write); pclose(fp_write); } return 0; }
一個(gè)讀取更多數(shù)據(jù)的例子
#include<stdio.h> #include<stdlib.h> int main(){ FILE* fp_read = popen("ps -ax", "r"); if(fp_read == NULL){ perror("create pipe to ps failed"); exit(EXIT_FAILURE); } char info[1024]; int num_char = fread(info, sizeof(char), 1024, fp_read); while(num_char>0){ info[num_char - 1] = '\0'; printf("got info: - \n%s\n", info); num_char = fread(info, sizeof(char), 1024, fp_read); } pclose(fp_read); exit(EXIT_SUCCESS); }
一個(gè)重要的系統(tǒng)調(diào)用是pipe,如同shell中的管道操作符
初始化兩個(gè)文件描述符組成的數(shù)組钳垮,一個(gè)用于讀惑淳,一個(gè)用于寫(xiě),一個(gè)簡(jiǎn)單的例子如下
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<sys/types.h> int main(){ int fd[2]; char buf[200]; int chpid; int len; //使用pipe系統(tǒng)調(diào)用創(chuàng)建一個(gè)管道扔枫,fd[0]用于讀取汛聚,fd[1]用于寫(xiě)入 if(pipe(fd) == -1){ perror("創(chuàng)建管道出錯(cuò):"); exit(1); } if((chpid = fork()) == 0){ close(fd[1]); //從fd[0]中讀取數(shù)據(jù)到buf緩沖區(qū) len = read(fd[0], buf, sizeof(buf)); buf[len] = 0; printf("子進(jìn)程從管道讀取數(shù)據(jù):%s\n", buf); exit(0); }else{ close(fd[0]); //sprintf函數(shù)將格式化數(shù)據(jù)寫(xiě)入緩沖區(qū)中 sprintf(buf, "父進(jìn)程為子進(jìn)程(pid=%d)創(chuàng)建的數(shù)據(jù)锹安!\n", chpid); //使用write系統(tǒng)調(diào)用將buf中的數(shù)據(jù)寫(xiě)入fd[1]指向的管道中 write(fd[1], buf, strlen(buf)); exit(0); } return 0; }
如上短荐,pipe創(chuàng)建的管道操作符僅僅用于相互有聯(lián)系的一組進(jìn)程,比如叹哭,父子進(jìn)程忍宋。當(dāng)我們?cè)跊](méi)有特殊聯(lián)系的進(jìn)程中想要相互聯(lián)系,可以通過(guò)命名管道fifo风罩,fifo是linux操作系統(tǒng)中一類(lèi)特殊的文件,用于進(jìn)程間通信
mode_t可以取
看一個(gè)生產(chǎn)者與消費(fèi)者的例子
fifo_producer.c#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #include<fcntl.h> #include<limits.h> #define BUF_SIZE 4096 #define TEN_SEG (1024 * 10) #define FIFO_NAME "/tmp/my_fifo" int main(){ int open_mode = O_WRONLY; int fifo_fd; int res; char buf[BUF_SIZE + 1]; if(access(FIFO_NAME, F_OK) == -1){ res = mkfifo(FIFO_NAME, 0777); if(res == -1){ fprintf(stderr, "can't create fifo file %s\n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("process %d open fifo O_WRONLY!\n", getpid()); fifo_fd = open(FIFO_NAME, open_mode); printf("process %d result %d\n", getpid(), fifo_fd); int bytes_sent = 0; if(fifo_fd != -1){ do{ res = write(fifo_fd, buf, BUF_SIZE); if(res == -1){ perror("error write data to fifo file"); exit(EXIT_FAILURE); } bytes_sent += res; }while(bytes_sent < TEN_SEG); (void)close(fifo_fd); }else{ exit(EXIT_FAILURE); } printf("process %d finished\n%d bytes sent!", getpid(), bytes_sent); exit(EXIT_SUCCESS); }
fifo_consumer.c
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<limits.h> #include<fcntl.h> #define BUF_SIZE 4096 #define FIFO_NAME "/tmp/my_fifo" int main(){ int res; int pipe_fd; int mode = O_RDONLY; if(access(FIFO_NAME, F_OK) == -1){ perror("fifo file not exists! exiting..."); exit(EXIT_FAILURE); } char recv[BUF_SIZE + 1]; int bytes_recv; printf("process %d open fifo file with mode O_RDONLY!\n", getpid()); pipe_fd = open(FIFO_NAME, mode); printf("open fifo file with result %d\n", pipe_fd); if(pipe_fd != -1){ do{ res = read(pipe_fd, recv, BUF_SIZE); bytes_recv += res; }while(res > 0); printf("%d bytes received!\n", bytes_recv); close(pipe_fd); }else{ exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
result
命名管道可用于多個(gè)進(jìn)程間相互通信糠排,客戶機(jī)服務(wù)器模式程序示例如下
client.h#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<limits.h> #include<fcntl.h> #include<sys/types.h> #include<sys/stat.h> #define SERVER_FIFO_NAME "/tmp/server_fifo" #define CLIENT_FIFO_NAME "/tmp/cli_%d_fifo" #define BUF_SIZE 50 struct data_to_pass_st{ pid_t pid; char some_data[BUF_SIZE - 1]; };
server.c
#include"client.h" #include<ctype.h> int main(){ int serv_fifo_fd, cli_fifo_fd; struct data_to_pass_st data; char buf[BUF_SIZE]; char cli_fifo_name[50]; int mode_serv; int mode_cli; serv_fifo_fd = mkfifo(SERVER_FIFO_NAME, 0777); if(serv_fifo_fd == -1){ perror("create server fifo failed!"); exit(EXIT_FAILURE); } puts("create server fifo"); mode_serv = O_RDONLY; serv_fifo_fd = open(SERVER_FIFO_NAME, mode_serv); if(serv_fifo_fd == -1){ perror("open server fifo failed!"); exit(EXIT_FAILURE); } puts("open server fifo"); sleep(1); printf("read to receive data!\n"); int read_bytes; char* tmp_ptr; do{ read_bytes = read(serv_fifo_fd, &data, sizeof(data)); if(read_bytes > 0){ tmp_ptr = data.some_data; while(*tmp_ptr){ *tmp_ptr = toupper(*tmp_ptr); tmp_ptr++; } sprintf(cli_fifo_name, CLIENT_FIFO_NAME, data.pid); cli_fifo_fd = open(cli_fifo_name, O_WRONLY); if(cli_fifo_fd != -1){ write(cli_fifo_fd, &data, sizeof(data)); close(cli_fifo_fd); } } }while(read_bytes > 0); close(serv_fifo_fd); unlink(SERVER_FIFO_NAME); exit(EXIT_SUCCESS); }
client.c
#include"client.h" #include<ctype.h> int main(){ struct data_to_pass_st data; char buf[BUF_SIZE]; char cli_fifo_name[50]; int serv_fifo_fd, cli_fifo_fd; serv_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY); puts("client : open server fifo"); if(serv_fifo_fd == -1){ perror("open server fifo failed"); exit(EXIT_FAILURE); } data.pid = getpid(); sprintf(cli_fifo_name, CLIENT_FIFO_NAME, data.pid); mkfifo(cli_fifo_name, 0777); puts("client : create client fifo"); int read_bytes; sprintf(data.some_data, "data from %d", data.pid); printf("%d sent: %s, ", data.pid, data.some_data); write(serv_fifo_fd, &data, sizeof(data)); cli_fifo_fd = open(cli_fifo_name, O_RDONLY); if(cli_fifo_fd == -1){ perror("open client fifo failed"); exit(EXIT_FAILURE); } if(cli_fifo_fd != -1){ read_bytes = read(cli_fifo_fd, &data, sizeof(data)); printf("received:%s\n", data.some_data); }else{ perror("open client fifo to read failed"); exit(EXIT_FAILURE); } close(cli_fifo_fd); close(serv_fifo_fd); exit(EXIT_SUCCESS); }
result
-
信號(hào)量,有時(shí)使用信號(hào)量完成進(jìn)程或線程同步
了解四個(gè)信號(hào)量操作函數(shù)
sem_init\sem_post\sem_wait\sem_destroy
example#include<stdio.h> #include<stdlib.h> #include<semaphore.h> #include<string.h> #include<pthread.h> char work_area[1024]; sem_t semaphore; void* thread_func(void* arg){ sem_wait(&semaphore); while(strncmp(work_area, "end", 3) != 0){ printf("len:%d\n", strlen(work_area) - 1); sem_wait(&semaphore); } pthread_exit(EXIT_SUCCESS); } int main(){ int res; pthread_t thread; void* thread_res; res = sem_init(&semaphore, 0, 0); if(res != 0){ perror("初始化信號(hào)量失敵入宦!"); exit(EXIT_FAILURE); } if((res = pthread_create(&thread, NULL, thread_func, NULL)) != 0){ perror("線程創(chuàng)建失敗"); exit(EXIT_FAILURE); } printf("please input a string:\n"); while(strncmp(work_area, "end", 3) != 0){ fgets(work_area, 1024, stdin); sem_post(&semaphore); } printf("wait for the thread exit!\n"); if((res = pthread_join(thread, &thread_res)) != 0){ perror("等待線程結(jié)束出錯(cuò)!"); exit(EXIT_FAILURE); } printf("線程已退出室琢!\n"); sem_destroy(&semaphore); exit(EXIT_SUCCESS); }
-
共享內(nèi)存
顧名思義乾闰,就是一塊兩者都可以訪問(wèn)的內(nèi)存,進(jìn)程通過(guò)原子性的寫(xiě)入操作保證數(shù)據(jù)完整性盈滴。
要點(diǎn):理解創(chuàng)建與操作共享內(nèi)存的系統(tǒng)調(diào)用涯肩,使用manual
看一個(gè)服務(wù)進(jìn)程與客戶進(jìn)程的例子
server.c#include"common.h" int main(){ int running = 1; void *share_mem; struct share_mem_st *data; int shmid; char buf[50]; shmid = shmget((key_t)1234, sizeof(struct share_mem_st), 0666 | IPC_CREAT); if(shmid == -1){ perror("create share_memory failed"); exit(EXIT_FAILURE); } share_mem = shmat(shmid, (void*)0, 0); if(share_mem == (void*)-1){ perror("attach the mem failed"); exit(EXIT_FAILURE); } printf("share memory attached at %X\n", share_mem); data = (struct share_mem_st*)share_mem; data->controller = 0; while(running){ while(data->controller == 1){ printf("wait for client...\n"); sleep(1); } puts("type the message:"); //fgets(buf, 50, stdin); memset(buf, '\0', 50); scanf("%s", buf); memset(data->message, '\0', TEXT_SIZE); strncpy(data->message, buf, strlen(buf)); data->controller = 1; if(strncmp(buf, "end", 3) == 0){ running = 0; } } printf("exiting...\n"); if(shmdt(share_mem) == -1){ perror("error between unttach the share_meme"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
client.c
#include"common.h" int main(){ int shmid; struct share_mem_st* data; void* share_mem; int running = 1; char buf[50]; if((shmid = shmget((key_t)1234, sizeof(struct share_mem_st), 0666 | IPC_CREAT)) == -1){ perror("create share mem failed"); exit(EXIT_FAILURE); } if((share_mem = shmat(shmid, (void*)0, 0)) == (void*)-1){ perror("attach the share mem failed"); exit(EXIT_FAILURE); } printf("share mem attach at %X\n", share_mem); data = (struct share_mem_st*)share_mem; data->controller = 1; while(running){ if(data->controller == 1){ strncpy(buf, data->message, strlen(data->message)); printf("message:%s\n", buf); sleep(2); data->controller = 0; if(strncmp(buf, "end", 3) == 0){ running = 0; } }else{ printf("waiting for server...\n"); sleep(1); } } if(shmdt(share_mem) == -1){ perror("unattach the share mem failed"); exit(EXIT_FAILURE); } if(shmctl(shmid, IPC_RMID, 0) == -1){ perror("error with release the share mem"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
-
消息隊(duì)列
隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),用于進(jìn)程間通信時(shí)較為靈活巢钓,可以設(shè)計(jì)為分布式病苗,十分適合與網(wǎng)絡(luò)應(yīng)用進(jìn)程通信,爬蟲(chóng)程序就是一個(gè)很好的例子
首先需要理解創(chuàng)建和使用消息隊(duì)列的一些系統(tǒng)調(diào)用-manual
一個(gè)使用消息隊(duì)列相互通信的例子
common.h#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #define BUF_SIZE 1024 struct msg_st{ long int msg_type; char data[BUF_SIZE]; };
server.c
#include"common.h" int main(){ int running = 1; struct msg_st msg_data; int msg_id; long int msg_type_receive = 1; if((msg_id = msgget((key_t)1234, 0666| IPC_CREAT)) == -1){ perror("server:can't create message queue"); exit(EXIT_FAILURE); } printf("get message queue with id:%d\n", msg_id); while(running){ if(msgrcv(msg_id, (void*)&msg_data, BUF_SIZE, msg_type_receive, 0) == -1){ perror("recv data from queue failed"); exit(EXIT_FAILURE); } printf("you wrote:%s\n", msg_data.data); if(strncmp(msg_data.data, "end", 3) == 0){ printf("exiting...\n"); running = 0; } } msgctl(msg_id, IPC_RMID, 0); exit(EXIT_SUCCESS); }
client.c
#include"common.h" int main(){ int running = 1; struct msg_st msg_data; long int msg_type_receive = 0; char buf[BUF_SIZE]; int msg_id; if((msg_id = msgget((key_t)1234, 0666 | IPC_CREAT)) == -1){ perror("client:get message queue failed"); exit(EXIT_FAILURE); } printf("get message queue with id:%d\n", msg_id); int length = 0; while(running){ memset(msg_data.data, '\0', BUF_SIZE); printf("input some text:"); fgets(buf, BUFSIZ, stdin); length = strlen(buf); msg_data.msg_type = 1; strncpy(msg_data.data, buf, length -1); msg_data.data[length] = '\0'; if(msgsnd(msg_id, (void*)&msg_data, BUF_SIZE, 0) == -1){ perror("error with send data"); exit(EXIT_FAILURE); } printf("you send:%s\n", msg_data.data); if(strncmp(buf, "end", 3) == 0){ printf("exiting...\n"); running = 0; } } exit(EXIT_SUCCESS); }
client
server
總結(jié)
信號(hào)症汹、管道硫朦、命名管道、共享內(nèi)存背镇、消息隊(duì)列以及信號(hào)量是進(jìn)程間通信的重要手段咬展,我們需要了解他們分別適用于何種情形花履,優(yōu)缺點(diǎn),如何使用挚赊,如何處理錯(cuò)誤诡壁,碰到不記得的函數(shù)用法,可以通過(guò)manual查看該函數(shù)聲明荠割,數(shù)據(jù)結(jié)構(gòu)等等信息妹卿。
五俯邓、進(jìn)程間通信
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锅很,“玉大人其馏,你說(shuō)我怎么就攤上這事”玻” “怎么了叛复?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)扔仓。 經(jīng)常有香客問(wèn)我褐奥,道長(zhǎng),這世上最難降的妖魔是什么翘簇? 我笑而不...
- 正文 為了忘掉前任撬码,我火速辦了婚禮,結(jié)果婚禮上缘揪,老公的妹妹穿的比我還像新娘耍群。我一直安慰自己,他們只是感情好找筝,可當(dāng)我...
- 文/花漫 我一把揭開(kāi)白布蹈垢。 她就那樣靜靜地躺著,像睡著了一般袖裕。 火紅的嫁衣襯著肌膚如雪曹抬。 梳的紋絲不亂的頭發(fā)上,一...
- 那天急鳄,我揣著相機(jī)與錄音谤民,去河邊找鬼堰酿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛张足,可吹牛的內(nèi)容都是我干的触创。 我是一名探鬼主播,決...
- 文/蒼蘭香墨 我猛地睜開(kāi)眼为牍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哼绑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碉咆,我...
- 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抖韩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后疫铜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體茂浮,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年壳咕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了席揽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
- 正文 年R本政府宣布程帕,位于F島的核電站住练,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏愁拭。R本人自食惡果不足惜讲逛,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岭埠。 院中可真熱鬧盏混,春花似錦、人聲如沸惜论。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)馆类。三九已至混聊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乾巧,已是汗流浹背句喜。 一陣腳步聲響...
- 正文 我出身青樓峡扩,卻偏偏與公主長(zhǎng)得像均驶,于是被迫代替她去往敵國(guó)和親登馒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拣播,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 大綱 一.Socket簡(jiǎn)介 二.BSD Socket編程準(zhǔn)備 1.地址 2.端口 3.網(wǎng)絡(luò)字節(jié)序 4.半相關(guān)與全相...
- 進(jìn)程間通信 ipc:interprocess communication 通信方式 管道通信Paste_Image...
- 參考鏈接:http://blog.csdn.net/sweetsnow24/article/details/863...
- 由于家境不好荡短,大學(xué)的時(shí)候桌吃,就開(kāi)始勤工儉學(xué)标沪,業(yè)余時(shí)間也去做了家教和家政榄攀。時(shí)間是忙碌而充實(shí)的。因?yàn)檫@些忙碌金句,我大學(xué)期間...