進程間通信-信號、共享內(nèi)存

信號概述

  • 信號是UNIX中所使用的進程通信的一種最古老的方法升酣。它是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式态罪。信號可以直接進行用戶空間進程和內(nèi)核進程之間的交互噩茄,內(nèi)核進程也可以利用它來通知用戶空間進程發(fā)生了哪些系統(tǒng)事件。它可以在任何時候發(fā)給某一進程向臀,而無需知道該進程的狀態(tài)。如果該進程當(dāng)前并未處于執(zhí)行態(tài)诸狭,則該信號就由內(nèi)核保存起來券膀,直到該進程恢復(fù)執(zhí)行再傳遞給它為止君纫。
  • 一個完整的信號生命周期可以分為3個重要階段,這3個階段由4個重要事件來刻畫的:包括信號產(chǎn)生芹彬、信號在進程中注冊蓄髓、信號在進程中注銷、執(zhí)行信號處理對應(yīng)的函數(shù) 舒帮。


信號常見的處理函數(shù)

  • 信號的處理包括信號的發(fā)送会喝、捕捉和處理,它們有各自相對應(yīng)的常見函數(shù):
    發(fā)生信號的函數(shù): kill()玩郊、raise()肢执。
    捕捉信號的函數(shù): alarm()、pause()译红。
    處理信號的函數(shù): signal()预茄、sigaction()。


  • 信號發(fā)送函數(shù)
  • kill()函數(shù)同讀者熟知的kill系統(tǒng)命令一樣侦厚,可以發(fā)送信號給進程或進程組(實際上耻陕,kill系統(tǒng)命令只是kill()函數(shù)的一個用戶接口)。這里需要注意的是刨沦,它不僅可以中止進程(實際上發(fā)出SIGKILL信號)诗宣,也可以向進程發(fā)送其他信號。
  • 與kill()函數(shù)所不同的是想诅,raise()函數(shù)允許進程向自身發(fā)送信號召庞。



  • 代碼實戰(zhàn)
    kill_raise.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>

int main()
{
    int ret;
    pid_t pid,pid_wait;
    pid=fork();
    if(pid<0)
    {
        printf("fork error!\n");
        return -1;
    }
    else if(pid==0)
    {
        printf("In child(%d) process,waiting for any signal\n",getpid());
        raise(SIGSTOP);
        exit(0);
    }
    else
    {
        
        if(pid_wait=waitpid(pid,NULL,WUNTRACED))
        {
            printf("Child(%d) is stop\n",pid_wait);
            if((ret=kill(pid,SIGKILL))==0)
                printf("In father process:\nParent kill process(%d)\n",pid);
        }
        
        /*
        if((waitpid(pid,NULL,WNOHANG))==0)
        {
            if((ret=kill(pid,SIGKILL))==0)
                printf("In father process:\nParent kill process(%d)\n",pid);
        }
        */
        waitpid(pid,NULL,0);
        exit(0);
    }
    return 0;
}
  • 信號捕捉函數(shù)
    alarm()也稱為鬧鐘函數(shù),它可以在進程中設(shè)置一個定時器侧蘸,當(dāng)定時器指定的時間到時裁眯,它就向進程發(fā)送SIGALARM信號。如果不忽略或不捕捉此信號讳癌,則其默認動作是終止該進程穿稳。要注意的是,一個進程只能有一個鬧鐘時間晌坤,如果在調(diào)用alarm()之前已設(shè)置過鬧鐘時間逢艘,則任何以前的鬧鐘時間都被新值所代替。
    pause()函數(shù)是用于將調(diào)用進程掛起直至捕捉到信號為止骤菠。這個函數(shù)很常用它改,通常可以用于判斷信號是否已到商乎。



  • 信號處理函數(shù)
    信號處理的主要方法有兩種央拖,一種是使用簡單的signal()函數(shù),另一種是使用信號集函數(shù)組。


信號響應(yīng)方式

  • 用戶進程對信號的響應(yīng)可以有3種方式鲜戒。
    忽略信號专控,即對信號不做任何處理,但是有兩個信號不能忽略遏餐,即SIGKILL及SIGSTOP伦腐。
    捕捉信號,定義信號處理函數(shù)失都,當(dāng)信號發(fā)生時柏蘑,執(zhí)行相應(yīng)的自定義處理函數(shù)。
    執(zhí)行缺省操作粹庞,Linux對每種信號都規(guī)定了默認操作咳焚。

共享內(nèi)存

  • 共享內(nèi)存是一種最為高效的進程間通信方式,進程可以直接讀寫內(nèi)存信粮,而不需要任何數(shù)據(jù)的拷貝
  • 為了在多個進程間交換信息黔攒,內(nèi)核專門留出了一塊內(nèi)存區(qū),可以由需要訪問的進程將其映射到自己的私有地址空間
  • 進程就可以直接讀寫這一內(nèi)存區(qū)而不需要進行數(shù)據(jù)的拷貝强缘,從而大大提高的效率督惰。
  • 由于多個進程共享一段內(nèi)存,因此也需要依靠某種同步機制旅掂,如互斥鎖和信號量等
  • Shell的ipcs命令可以查看共享內(nèi)存情況


  • 共享內(nèi)存使用步驟
    1)創(chuàng)建/打開共享內(nèi)存赏胚;
    2)映射共享內(nèi)存,即把指定的共享內(nèi)存映射到進程的地址空間用于訪問商虐;
    3)分離/撤銷共享內(nèi)存映射觉阅;
    4)刪除共享內(nèi)存對象;


  • 共享內(nèi)存創(chuàng)建



    key : 和信號量一樣秘车,程序需要提供一個參數(shù)key,它有效地為共享內(nèi)存段命名典勇。有一個特殊的鍵值IPC_PRIVATE, 它用于創(chuàng)建一個只屬于創(chuàng)建進程的共享內(nèi)存,僅用于有親緣關(guān)系的進程間通信叮趴。
    size: 以字節(jié)為單位指定需要共享的內(nèi)存容量割笙。
    shmflag: 包含9個比特的權(quán)限標(biāo)志,它們的作用與創(chuàng)建文件時使用的mode標(biāo)志是一樣眯亦。
    讀寫的權(quán)限還有IPC_CREAT或IPC_EXCL對應(yīng)文件的O_CREAT或O_EXCL
    權(quán)限標(biāo)志對共享內(nèi)存非常有用伤溉,因為它允許一個進程創(chuàng)建的共享內(nèi)存可以被共享內(nèi)存的創(chuàng)建者所擁有的進程寫入,同時其它用戶創(chuàng)建的進程只能讀取共享內(nèi)存妻率。
    我們可以利用這個功能來提供一種有效的對數(shù)據(jù)進行只讀訪問的方法乱顾,通過將數(shù)據(jù)放共享內(nèi)存并設(shè)置它的權(quán)限,就可以避免數(shù)據(jù)被其他用戶修改宫静。

  • ftok
    同一段程序走净,為保證兩個不同用戶下的兩組相同程序獲得互不干擾的IPC鍵值券时,通常利用ftok函數(shù)將文件節(jié)點和一個id值組合生成一個唯一的IPC鍵值。
    ftok原型如下:key_t ftok( char * fname, int id )
    fname就時你指定的文件名(該文件必須是存在而且可以訪問的)伏伯,
    id是子序號革为,雖然為int,但是只有8個比特被使用(0-255)舵鳞。
    當(dāng)成功執(zhí)行的時候,一個key_t值將會被返回琢蛤,否則 -1 被返回蜓堕。

    使用 ftok創(chuàng)建共享內(nèi)存,毫無關(guān)系的進程也可以通過得到同樣的key博其,來操作同一個共享內(nèi)存套才,在對共享內(nèi)存進行讀寫時,需要利用信號量進行同步或互斥慕淡。
    使用IPC_PRIVATE創(chuàng)建的IPC對象, 和無名管道類似背伴,只可以用于有親緣關(guān)系的進程間通信。
  • 共享內(nèi)存映射函數(shù)
    作用:將共享內(nèi)存映射到本進程地址空間峰髓,以實現(xiàn)本進程對該共享內(nèi)存區(qū)的訪問傻寂。
    注意:共享內(nèi)存的讀寫權(quán)限由它的屬主(共享內(nèi)存的創(chuàng)建者)決定,它的訪問權(quán)限由當(dāng)前進程的屬主決定携兵。


  • 共享內(nèi)存分離
    作用:將共享內(nèi)存從當(dāng)前進程空間分離疾掰。
    注意:共享內(nèi)存分離并未刪除它,只是使得該共享內(nèi)存對當(dāng)前進程不再可用徐紧。


  • 共享內(nèi)存控制
    函數(shù)作用:實現(xiàn)對共享內(nèi)存的控制



    shmid_ds結(jié)構(gòu)至少包含以下成員:

struct shmid_ds  
{  
    uid_t shm_perm.uid;  
    uid_t shm_perm.gid;  
    mode_t shm_perm.mode;  
}; 
  • 共享內(nèi)存代碼實戰(zhàn):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>

#define BUFFER_SIZE 1024

struct share_mm//共享內(nèi)存結(jié)構(gòu)體
{
    int flag_wrote;
    char buf[BUFFER_SIZE];
};

int main()
{
    int shmid;
    pid_t pid;
    struct share_mm * shmaddr;//保存映射地址
    //創(chuàng)建共享內(nèi)存
    shmid = shmget(IPC_PRIVATE,sizeof(struct share_mm),0666);
    if(shmid==-1)
    {
        printf("shmget error\n");
        exit(1);
    }
    else
    {
        printf("Shmid is %d\n",shmid);
        system("ipcs -m");
    }
    //創(chuàng)建子進程
    pid = fork();
    if(pid==-1)
    {
        printf("fork error\n");
        exit(1);
    }
    else if(pid==0)//in child process
    {
        shmaddr=shmat(shmid,0,0);//映射静檬,并獲得映射地址
        if(shmaddr==(void *)-1)
        {
            printf("shmat error\n");
            exit(1);
        }
        else
        {
            printf("Child attach shm is %p\n",shmaddr);
            system("ipcs -m");
        }
        
        do
        {
            if(shmaddr->flag_wrote!=1)//判斷父進程是否寫數(shù)據(jù)到共享內(nèi)存
            {
                printf("Wait father write message!!\n");
                while(shmaddr->flag_wrote!=1);//等待父進程寫數(shù)據(jù)
                printf("From father message:%s\n",shmaddr->buf);
                shmaddr->flag_wrote=0;//標(biāo)記數(shù)據(jù)已讀走
            }
        }while(strncmp(shmaddr->buf,"quit",4));
        
        printf("Father byebye\n");
        if((shmdt(shmaddr))<0)//刪除地址映射
        {
            printf("shmdt error\n");
            exit(1);
        }
        exit(0);
    }
    else //in fater process
    {
        shmaddr=shmat(shmid,0,0);
        if(shmaddr==(void *)-1)
        {
            printf("shmat error\n");
            exit(1);
        }
        else
        {
            printf("Father attach shm is %p\n",shmaddr);
            system("ipcs -m");
        }
        shmaddr->flag_wrote=0;
        do
        {
            if(shmaddr->flag_wrote==0)//判斷數(shù)據(jù)是否被子進程讀走
            {
                memset((void *)shmaddr->buf,0,BUFFER_SIZE);
                printf("In father process:\nPlease write message\n");
                gets(shmaddr->buf);//從鍵盤寫入數(shù)據(jù)到共享內(nèi)存
                shmaddr->flag_wrote=1;//標(biāo)記已寫數(shù)據(jù)
            }
        }while(strncmp(shmaddr->buf,"quit",4));
        
        waitpid(pid,NULL,0);//等待子進程先退出
        printf("Child byebye\n");
        if((shmdt(shmaddr))<0)
        {
            printf("shmdt error\n");
            exit(1);
        }
        if((shmctl(shmid,IPC_RMID,NULL))<0)//刪除內(nèi)核中的共享內(nèi)存
        {
            printf("shmctl error\n");
            exit(1);
        }
        exit(0);
    }
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市并级,隨后出現(xiàn)的幾起案子拂檩,更是在濱河造成了極大的恐慌,老刑警劉巖嘲碧,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稻励,死亡現(xiàn)場離奇詭異,居然都是意外死亡呀潭,警方通過查閱死者的電腦和手機钉迷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钠署,“玉大人糠聪,你說我怎么就攤上這事⌒扯Γ” “怎么了舰蟆?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵趣惠,是天一觀的道長。 經(jīng)常有香客問我身害,道長味悄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任塌鸯,我火速辦了婚禮侍瑟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丙猬。我一直安慰自己涨颜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布茧球。 她就那樣靜靜地躺著庭瑰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抢埋。 梳的紋絲不亂的頭發(fā)上弹灭,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音揪垄,去河邊找鬼穷吮。 笑死,一個胖子當(dāng)著我的面吹牛饥努,可吹牛的內(nèi)容都是我干的酒来。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼肪凛,長吁一口氣:“原來是場噩夢啊……” “哼堰汉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伟墙,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤翘鸭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后戳葵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體就乓,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年拱烁,在試婚紗的時候發(fā)現(xiàn)自己被綠了裸删。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漓滔。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡廊鸥,死狀恐怖邓嘹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情擅笔,我是刑警寧澤志衣,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布屯援,位于F島的核電站,受9級特大地震影響念脯,放射性物質(zhì)發(fā)生泄漏狞洋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一绿店、第九天 我趴在偏房一處隱蔽的房頂上張望吉懊。 院中可真熱鬧,春花似錦假勿、人聲如沸惕它。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至郁惜,卻和暖如春堡距,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背兆蕉。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工羽戒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虎韵。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓易稠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親包蓝。 傳聞我的和親對象是個殘疾皇子驶社,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容