1. 程式人生 > >Linux學習之程序通訊(二)

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;
}

到此為止訊號的發文送相關的函式就已經說完了。