?? 3.進(jìn)程間通信(ipc).txt
字號(hào):
3.進(jìn)程間通信(IPC)
信號(hào)機(jī)制
信號(hào)是一中異步事件(也稱軟中斷),可通過信號(hào)機(jī)構(gòu)停止一個(gè)程序。
一個(gè)信號(hào)必定有他的發(fā)送者,接收者。一個(gè)信號(hào)的意義必須事先定義。
信號(hào)表是把信號(hào)和信號(hào)處理函數(shù)一一對應(yīng)的一個(gè)表結(jié)構(gòu),Unix定義了37種信號(hào)。
注意:信號(hào)會(huì)打斷任何的系統(tǒng)阻塞。
信號(hào)的處理
信號(hào)的處理有三種,忽略,捕獲,默認(rèn)方式(default)。
信號(hào)的處理多用捕獲和默認(rèn)方式來處理。
捕獲是通過自定義的函數(shù)去替換信號(hào)表中的默認(rèn)函數(shù)。
幾種重要的信號(hào)
SIGALRM,超時(shí)信號(hào)(alram函數(shù)設(shè)置時(shí)鐘到時(shí)后的發(fā)出的信號(hào))
SIGCHLD,當(dāng)子進(jìn)程中止時(shí)調(diào)用,此信號(hào)會(huì)發(fā)送給子進(jìn)程的父進(jìn)程,父進(jìn)程會(huì)回收子進(jìn)程資源,而不必等待子進(jìn)程結(jié)束,可以運(yùn)行自身的代碼,這也就達(dá)到了異步運(yùn)行的目的。(常用信號(hào))
SIGINT,此信號(hào)用于中止失控程序(按ctrl+c組合和delete鍵會(huì)發(fā)送此信號(hào))
SIGKILL,強(qiáng)制殺死進(jìn)程的信號(hào),此信號(hào)不能互略和捕獲,只能按系統(tǒng)默認(rèn)方式處理。
SIGSTOP,作業(yè)控制信號(hào),可以停止一個(gè)進(jìn)程,此信號(hào)之能按系統(tǒng)默認(rèn)方式處理。
SIGUSR1,SIGUSR2,這兩個(gè)是系統(tǒng)留給用戶自定義的信號(hào),一般多使用兩個(gè)信號(hào),并進(jìn)行捕獲處理。
其余信號(hào)參見課本
system()函數(shù)創(chuàng)建到子進(jìn)程會(huì)忽略SIGINT,SIGQUIT兩種信號(hào)。
signal函數(shù)
signal函數(shù),是用來修改信號(hào)表中信號(hào)對應(yīng)的處理函數(shù)。
typedef void(*FUNC)(int)定義函數(shù)指針,int參數(shù)帶表的是實(shí)際收到的信號(hào)。
FUNC signal(int signo,FUNC fp)<signal.h>信號(hào)注冊函數(shù),
signal函數(shù)的返回值是原來的信號(hào)處理函數(shù)。
signo參數(shù)要是用信號(hào)的名字。(信號(hào)名本身是定義好的宏)
注意:signal函數(shù)在實(shí)際使用時(shí),只需要傳入自定的函數(shù)名即可。自定義的信號(hào)處理函數(shù)需要特定的結(jié)構(gòu)
即void 函數(shù)名(int)。當(dāng)信號(hào)接收后會(huì)調(diào)用相應(yīng)的信號(hào)處理函數(shù),也就是注冊了的自定義函數(shù)。
注意:Unix中會(huì)有信號(hào)丟失處理,signal函數(shù)只是注冊后運(yùn)行結(jié)束前有效。注冊一次后,就只有這一次有效,所以可以在自定的信號(hào)捕獲函數(shù)中遞歸的調(diào)用signal函數(shù),這樣可以避免信號(hào)丟失。也就使在信號(hào)處理函數(shù)中再調(diào)用signal函數(shù)注冊這個(gè)信號(hào)處理函數(shù)。
SIG_ERR捕獲信號(hào)失敗,SIG_DFL系統(tǒng)默認(rèn)行為,SIG_IGN忽略信號(hào),這些可以做signal函數(shù)的參數(shù)值也是返回值,可以判斷信號(hào)是否捕獲成功,或者是自定義信號(hào)處理函數(shù)是否注冊成功。
注意:在Unix中所有阻塞函數(shù)都會(huì)被信號(hào)打斷。
kill命令和kill函數(shù)
kill,命令 kill -sig pid(進(jìn)程id)可向任意進(jìn)程發(fā)出信號(hào)。
sig,去掉信號(hào)名前的SIG三個(gè)字母后信號(hào)的名字
注意:這里的參數(shù)sig,就是去掉信號(hào)名前的SIG三個(gè)字母。
kill函數(shù)
int kill(pid_t pid,int sig)<sys/types.h><signal.h>,用于在程序中向任意進(jìn)程發(fā)出信號(hào)。pid是進(jìn)程id。sig是信號(hào)的全名。
信號(hào)的自舉
int raise(int sig),程序本身自己向自己發(fā)信號(hào),sig是信號(hào)的全名。
alarm函數(shù)
unsigned alarm(unsigned int sec)<unistd.h><signal.h>
sec是指定的時(shí)間。
這個(gè)函數(shù)的功能是從現(xiàn)在起的設(shè)定的時(shí)間間隔后發(fā)出一個(gè)SIGALRM信號(hào)。SIGALRM,信號(hào)的默認(rèn)處理是進(jìn)程中止退出。我們可以通過重新注冊信號(hào)處理函數(shù)來實(shí)現(xiàn)相應(yīng)功能。
sec是時(shí)間間隔的描述。
pause函數(shù)
int pause()<unistd.h>永久阻塞函數(shù),直到信號(hào)打斷后才會(huì)結(jié)束阻塞。
sleep函數(shù)
unsigned sleep(unsigned int sec)<unistd.h>是進(jìn)程進(jìn)入睡眠狀態(tài)制定的時(shí)間。
sec是指定的時(shí)間。
sleep函數(shù)在被打斷后會(huì)返回沒有睡夠的秒數(shù)。
Daemon進(jìn)程
父進(jìn)程和子進(jìn)程的進(jìn)程組id相同,會(huì)話包含多個(gè)進(jìn)程組。
Daemon進(jìn)程是在終端關(guān)閉后不會(huì)結(jié)束的進(jìn)程。
Daemon進(jìn)程的父進(jìn)程的id是1,也就是intit進(jìn)程。他的進(jìn)程組的id和會(huì)話的id是相同的,就是他本身,不使用控制終端。
//父進(jìn)程id為1
pid_t=fork();
if(pid>0)exit();
//進(jìn)程組id和會(huì)話id為本身
setsid();
//設(shè)置屏蔽字
umask(0);
for(int i=0;i<255;i++){
close(i);
}
以上是Daemon進(jìn)程的標(biāo)準(zhǔn)寫法
FIFO管道文件
使用FIFO時(shí)要包含<sys/types.h><sys/stat.h>兩個(gè)頭文件。
mkfifo 文件名,創(chuàng)建管道文件命令。
int mkfifo(const char* pathname,mode_t mode)<sys/types.h><sys/stat.h>創(chuàng)建管道文件。
pathname是管道文件的文件名,mode是文件的權(quán)限。
mkfifo函數(shù)的返回值表示FIFO文件創(chuàng)建是否成功,不是文件描述符。
使用FIFO的條件
(1)必須是兩個(gè)進(jìn)程同時(shí)對FIFO類型文件進(jìn)行操作,并分別以只讀和只寫的方式才能打開FIFO文件,否則open函數(shù)會(huì)阻塞。
(2)read()函數(shù)的返回值為0表示文件讀取完畢,表示寫入方關(guān)閉了FIFO文件。
(3)FIFO文件在讀取之后會(huì)自動(dòng)清空,F(xiàn)IFO文件事先寫入后讀取,可以用于多進(jìn)程間的通信。
Message Queue(消息隊(duì)列)
注意:使用消息隊(duì)列需要包含<sys/types.h><sys/ipc.h><sys/msg.h>三個(gè)頭文件。
消息隊(duì)列,實(shí)質(zhì)上是一個(gè)由內(nèi)核維護(hù)的消息鏈表,是用msqid作為消息隊(duì)列的唯一標(biāo)識(shí)。可以用ipcs來查詢消息隊(duì)列。用ipcrm 消息隊(duì)列id,刪除消息隊(duì)列。
消息隊(duì)列的操作
創(chuàng)建消息隊(duì)列
int msgget(key_t key,int flag)創(chuàng)建消息隊(duì)列。
參數(shù)key也是用以標(biāo)識(shí)消息隊(duì)列的值,key一般定義在頭文件中。(可以用IPC_PRIVATE隨機(jī)生成key)
注意:key是在創(chuàng)建時(shí)用于查找相應(yīng)的key值,如果查找到key值相同的消息隊(duì)列就不創(chuàng)建新的隊(duì)列了,而是使用這個(gè)隊(duì)列,如果沒有就會(huì)去查第二個(gè)參數(shù),如果標(biāo)識(shí)為新建會(huì)創(chuàng)建一個(gè)消息隊(duì)列,如果不是會(huì)出錯(cuò)
flag是一個(gè)標(biāo)記,一般在創(chuàng)建時(shí)寫成 (IPC_CREATE|權(quán)限)(權(quán)限設(shè)置和文件相同),如果置為0就會(huì)用key去查找已有的消息隊(duì)列,不會(huì)創(chuàng)建新的消息隊(duì)列。
創(chuàng)建消息隊(duì)列的返回值就是消息隊(duì)列的msqid。如果返回值小于0就表示創(chuàng)建失敗。
注意:如果要取得已創(chuàng)建的消息隊(duì)列,就要把第二參數(shù),設(shè)為0,key值傳入要找的那個(gè)隊(duì)列的key。
刪除消息隊(duì)列
int msgctl(int msqid,int cmd,struct msqid_ds* buf)刪除消息隊(duì)列。
msqid是要?jiǎng)h除的消息隊(duì)列的msqid
cmd,在刪除消息隊(duì)列時(shí)使用IPC_RMID這個(gè)值(其含義是立即刪除消息隊(duì)列),其他的選項(xiàng)還有IPC_STAT是取此隊(duì)列的msqid_ds的結(jié)構(gòu),IPC_SET這個(gè)是用傳入的參數(shù)buf,來修改msqid_ds結(jié)構(gòu)。
msqid_ds這個(gè)結(jié)構(gòu)規(guī)定了當(dāng)前狀態(tài)。
buf這個(gè)參數(shù)只有在使用cmd為IPC_SET時(shí)才使用,其余cmd在使用這個(gè)參數(shù)時(shí)用NULL即可。
注意:刪除消息隊(duì)列的常用方式 msgctl(mspid,IPC_RMID,NULL),消息隊(duì)列在使用完之后需要?jiǎng)h除。
發(fā)送/接收消息
在消息隊(duì)列中存放是引種規(guī)定了格式結(jié)構(gòu)的消息。
標(biāo)準(zhǔn)的msg結(jié)構(gòu),這種結(jié)構(gòu)就是放在消息隊(duì)列中發(fā)送或者是接收的“消息”。這個(gè)結(jié)構(gòu)中第一個(gè)成員是一個(gè)long型的變量,除此之外,可以在這個(gè)結(jié)構(gòu)中的定義其他的任意數(shù)量,任意類型的成員。
struct msg{
long msgtype;//這個(gè)變量表示的是消息的類型,用以區(qū)分消息的內(nèi)容,這樣就可以使一個(gè)消息隊(duì)列中可以存放多種消息。
char mtext[MAX_MSG_LENGTH];//消息的正文部分。這里用的是字符串類型,也可以使用其他的類型作為消息的正文。
}
int msgsnd(int msqid,const void* ptr,size_t nbytes,int flag)發(fā)送消息
int msgrcv(int msqid,void* ptr,size_t nbytes, long type,int flag)接受消息
msgid,都是消息隊(duì)列的標(biāo)識(shí),就是要想哪個(gè)消息隊(duì)列寫消息,要從哪個(gè)消息隊(duì)列讀取消息。
const void* ptr,是要發(fā)送的消息的地址。(消息就是消息結(jié)構(gòu)的變量)
void* ptr,是接收消息的空間。
nbytes,是要發(fā)送的消息的大小(長度)。
type,是要接受的消息的類型(如果接收類型設(shè)置為0,就表示接收所有消息)
flag,是一個(gè)標(biāo)記位,一般用0作為它的值。
注意:如果要接收一個(gè)沒有的消息結(jié)構(gòu)的類型,msgrcv函數(shù)會(huì)阻塞直到有這種消息結(jié)構(gòu)類型的消息被發(fā)出。這種阻塞也可以被信號(hào)打斷。
make命令
make命令使用與多文件編譯或者多名令執(zhí)行的腳本文件執(zhí)行命令。make可以控制編譯過程,只編譯需要編譯的文件。
makefile 命令用于創(chuàng)建腳本文件。
腳本文件格式
目標(biāo)文件名:條件1 條件2
(按table鍵)命令.....
目標(biāo)文件名(條件1):條件a
(按table鍵)命令.....
當(dāng)要得到的文件還需要起他條件時(shí)就以此類推。
創(chuàng)建條件文件的命令寫在目標(biāo)文件的下一行且要在開頭按table鍵。
腳本文件中可以定義宏,格式是例:cc=g++ ,是用宏是用${cc}
還可用占位符替代條件和相同的目標(biāo)名,“${@}”在同一個(gè)目標(biāo)中,可以以此替代目標(biāo)名,“${?}”這個(gè)可以替換條件名。 用#開就是注釋。
事例:
CC=g++
COMPIL=-c
NAME=-o
cat_test : cat_impl.o cat_main.o
${CC} ${NAME} ${@} cat_impl.o cat_main.o ;
rm *.o
cat_impl.o : cat_impl.cc
${CC} ${NAME} ${@} ${COMPIL} cat_impl.cc
cat_main.o : cat_main.cc
${CC} ${NAME} ${@} ${COMPIL} cat_main.cc
動(dòng)態(tài)連接庫
寫一個(gè)頭文件,頭文件中定義了函數(shù),然后寫.cc文件實(shí)現(xiàn)函數(shù),動(dòng)態(tài)連接庫一定要是libxxxx.so(LIUX/UNIX)這種格式。
現(xiàn)將.cc文件編譯成.o文件
g++ -c -o xxx.o xxx.cc
g++ libxxx.so -shared xxx.o(目標(biāo)文件)
動(dòng)態(tài)連接庫的使用
在主函數(shù)中調(diào)用了動(dòng)態(tài)連接庫中的函數(shù)
需要指定動(dòng)態(tài)連接庫的位置,要對環(huán)境變量進(jìn)行修改(LD_LIBRARY_PATH)添加上自己定義的動(dòng)態(tài)連接庫的路徑。
連接庫是使用的名字(xxx)是去掉lib和.so就可以了
g++ sample.cc -lxxx -Lxxx
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -