Linux學習之程序通訊(二)
言之者無罪,聞之者足以戒。 ——《詩序》
命令:kill -l 可以檢視核心可以傳送多少種訊號
命令:ps -axj 可以檢視程序的狀態
訊號:
訊號通訊,其實就是核心向用戶空間程序傳送訊號,只有核心才能發訊號,使用者空間程序不能傳送訊號
訊號通訊的框架:
(1)訊號的傳送(傳送訊號的程序):kill() 、raise() 、alarm()
(2)訊號的接收(接收訊號程序):pause()、sleep()、while(1)
(3)訊號的處理(接收訊號程序):signal()
一、訊號的傳送(傳送訊號的處理)
1、kill: 殺死一個程序
所需標頭檔案 |
#include <signal.h> #include <sys/types.h> |
|
函式原型 |
int kill(pid_t pid, int sig); |
|
函式傳入值 |
pid: |
正數:要接收訊號的程序的程序號 |
0:訊號被髮送到所有和pid程序在同一個程序組的程序 |
||
-1:訊號發給所有的程序表中的程序(除了程序號最大的程序外) |
||
sig:訊號 |
||
函式返回值 |
成功:0 |
|
出錯:-1 |
下面來看一下程式碼:
第一個程式:
#include <unistd.h> #include <sys/types.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]) { int sig; int pid; if(argc <3) { printf("please input:\n"); return -1; } sig=atoi(argv[1]); pid=atoi(argv[2]); printf("sig=%d,pid=%d\n",sig,pid); kill(pid,sig); return 0; }
第二個程式:
#include <stdio.h>
int main()
{
while(1);
return 0;
}
上面的程式實現的就是呼叫kill()函式來實現殺死正在執行的程序。
2、raise:傳送訊號給自己
所需標頭檔案 |
#include <signal.h> #include <sys/types.h> |
函式原型 |
int raise(int sig); |
函式傳入值 |
sig:訊號 |
函式返回值 |
成功:0 |
出錯:-1 |
下面我們用程式來學習一下這個函式:
include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main()
{
printf("raise befor\n");
raise(9);
printf("raise after");
return 0;
}
下面用kill()函式和raise()函式來改變程序的狀態:
#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
pid_t pid;
pid=fork();
if(pid >0)
{
sleep(8);
if(waitpid(pid,NULL,WNOHANG));
{
kill(pid,9);
}
wait(NULL);
while(1);
}
if(pid == 0)
{
printf("raise function befoer\n");
raise(SIGTSTP);
printf("raise function after\n");
exit(0);
}
return 0;
}
(1)、wait函式:
wait(int *status)
程序一旦呼叫了wait函式,就會立即阻塞自己,由wait函式自動分析是否當前程序的某個子程序已經退出,如果讓它找到了這樣一個已經變成殭屍的子程序,wait就會收集這個子程序的資訊,並把它徹底銷燬後返回;如果沒有找到這樣一個子程序,wait就會一直阻塞在這裡,直到有一個這樣的子程序出現為止。
引數status用來保護被 收集程序退出時的一些狀態,它是一個指向int型別的指標。但如果我們對這個子程序是如何死掉的毫不在意,只是想把這個殭屍程序消滅掉(事實上絕大多數情況我們都是這樣的),我們就可以設定這個引數為NULL,
例如:pid=wait(NULL);如果成功,wait會返回被收集的子程序的程序ID,如果呼叫程序沒有子程序,呼叫就會失敗,此時wait返回-1,同時errno被置為ECHILD。
(2)、waitpid函式:
pid_t wait(pid_t pid,int *status,int options)
pid :程序的ID,但當pid取值不同時,意義也不同
pid >0:只等待程序ID等於pid的子程序,不管其他已經有多少子程序執行結束退出了,只要指定的子程序還沒結束,waitpid就一直等下去。
pid =-1:等待任何一個子程序的退出,沒有任何限制,此時waitpid和wait的作用一樣
pid=0:等待同一個程序組中的任何子程序,如果子程序已經加入了別的程序組,waitpid不會對它做任何理睬
pid< -1:等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值
引數status用來保護被 收集程序退出時的一些狀態,它是一個指向int型別的指標。但如果我們對這個子程序是如何死掉的毫不在意,只是想把這個殭屍程序消滅掉(事實上絕大多數情況我們都是這樣的),我們就可以設定這個引數為NULL
opion:目前在Linux中只支援WNOHANG和WUNTRACED兩個選項,使用WNOHANG引數呼叫waitpid,即使沒有子程序退出,它也會立即返回,不會像wait那樣永遠等下去。如果兩個都不用可以直接寫0。
返回值和錯誤 :
waitpid的返回值比wait稍微複雜一些,一共有3種情況:
1、當正常返回的時候,waitpid返回收集到的子程序的程序ID;
2、如果設定了選項WNOHANG,而呼叫中waitpid發現沒有已退出的子程序可收集,則返回0;
3、如果呼叫中出錯,則返回-1,這時errno會被設定成相應的值以指示錯誤所在;
當pid所指示的子程序不存在,或此程序存在,但不是呼叫程序的子程序,waitpid就會出錯返回,這時errno被設定為ECHILD;
(3)、exit函式
exit()函式關閉所有開啟的檔案並終止程式。
exit()函式的引數會被傳遞給一些作業系統,通常的約定是正常終止的程式傳遞值0,非正常終止的程式傳遞非0值
3、alarm:傳送鬧鐘訊號的函式
alarm與raise函式的比較:
相同點:讓核心傳送訊號給當前程序
不同點:
(1)alarm只會傳送SIGALARM訊號
(2)alarm會讓核心定時一段時間之後傳送訊號,raise會讓核心立刻傳送訊號
所需標頭檔案 |
#include <unistd.h> |
函式原型 |
unsigned int alarm(unsigned int seconds) |
函式傳入值 |
seconds:指定秒數 |
函式返回值 |
成功:如果呼叫此alarm()前,程序中已經設定了鬧鐘時間,則 返回上一個鬧鐘時間的剩餘時間,否則返回0。 |
出錯:-1 |
訊號名 |
含義 |
預設操作 |
SIGHUP |
該訊號在使用者終端連線(正常或非正常)結束時發出,通常是在終端的控制程序結束時,通知同一會話內的各個作業與控制終端不再關聯。 |
終止 |
SIGINT |
該訊號在使用者鍵入INTR字元(通常是Ctrl-C)時發出,終端驅動程式傳送此訊號並送到前臺程序中的每一個程序。 |
終止 |
SIGQUIT |
該訊號和SIGINT類似,但由QUIT字元(通常是Ctrl-\)來控制。 |
終止 |
SIGILL |
該訊號在一個程序企圖執行一條非法指令時(可執行檔案本身出現錯誤,或者試圖執行資料段、堆疊溢位時)發出。 |
終止 |
SIGFPE |
該訊號在發生致命的算術運算錯誤時發出。這裡不僅包括浮點運算錯誤,還包括溢位及除數為0等其它所有的算術的錯誤。 |
終止 |
SIGKILL |
該訊號用來立即結束程式的執行,並且不能被阻塞、處理和忽略。 |
終止 |
SIGALRM |
該訊號當一個定時器到時的時候發出。 |
終止 |
SIGSTOP |
該訊號用於暫停一個程序,且不能被阻塞、處理或忽略。 |
暫停程序 |
SIGTSTP |
該訊號用於暫停互動程序,使用者可鍵入SUSP字元(通常是Ctrl-Z)發出這個訊號。 |
暫停程序 |
SIGCHLD |
子程序改變狀態時,父程序會收到這個訊號 |
忽略 |
SIGABORT |
該訊號用於結束程序 |
終止 |
下面給出一段程式:
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main()
{
int i=0;
printf("alarm befor\n");
alarm(8);
printf("alarm after\n");
while(i < 20)
{
printf("process working time is %d\n",i);
i++;
sleep(1);
}
return 0;
}
到此為止訊號的發文送相關的函式就已經說完了。