1. 程式人生 > >linux進程間通信--信號通信

linux進程間通信--信號通信

seconds main 回收 定時 void 發生 error ces 進程間

信號

信號是異步進程間通信方式

進程對信號的響應方式:
<1>忽略
SIGKILL 和 SIGSTOP 不能忽略

<2>捕捉
當進程收到信號,此時執行的信號處理函數

<3>默認

SIGSTOP 改信號用於暫停一個進程,且不能被阻塞,忽略,和處理,默認操作為暫停進程
大部分信號對進程的默認操作方式都是殺死進程
子進程狀態發生改變的時候,操作系統向父進程發送SIGCHLD,默認對它處理方式是忽略

信號的發送與設置

1.信號發送 kill()與raise()

int kill(pid_t pid, int sig);

參數:
pid:可能選擇有以下四種

1. pid大於零時,發送信號給進程號為pid的進程。
2. pid等於零時,信號將送往所有與調用kill()的那個進程屬同一個使用組的進程。
3. pid等於-1時,信號發送給所有的進程表中的進程,除了進程1(init)。
4. pid小於-1時,信號將送往以-pid為組標識的進程。

sig:準備發送的信號代碼,假如其值為零則沒有任何信號送出,但是系統會執行錯誤檢查,通常會利用sig值為零來檢驗某個進程是否仍在執行。


返回值說明: 成功執行時,返回0。失敗返回-1

errno被設為以下的某個值:

EINVAL:指定的信號碼無效(參數 sig 不合法)

EPERM:權限不夠無法傳送信號給指定進程

ESRCH:參數 pid 所指定的進程或進程組不存在

int raise(int signo);

註意:raise函數只允許進程向自身發送信號

實例如下:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char *argv[])
{

  pid_t pid;
  int ret;

if((pid=fork())<0)
{
  printf("Fork error\n");
  exit(EXIT_FAILURE);
}
if(pid==0)
{
  printf("child(pid:%d) is waiting for any signal\n",getpid());
  raise(SIGSTOP);//在子進程中使用raise()函數發出SIGSTOP信號,使子進程暫停
  exit(EXIT_SUCCESS);
}
else
{
  if(waitpid(pid,NULL,WNOHANG)==0)
  {
    sleep(10);
    kill(pid,SIGKILL);
    printf("parent kill child process %d\n",pid);
  }
}
waitpid(pid,NULL,0);
return 0;
}

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:設置進程對信號處理方式
參數:
@signum 信號的編號
@handler
SIG_IGN : 忽略信號
SIG_DFL : 使用默認處理方式
函數名 : 捕捉方式處理

返回值:
成功返回handler,失敗返回SIG_ERR

練習:
如何進行不阻塞,不輪訓方式回收僵屍態子進程


2.在進程中設置一個定時器

unsigned int alarm(unsigned int seconds);
參數:
@seconds 定時的時間,以秒為單位

註意:
一旦定時時間完成,操作系統就會向進程發送SIGALRM信號

作業:
通過有名管道完成文件傳輸

./A file1 ------->fifo -------> ./B file2

A進程:
讀文件,寫管道

A進程結束條件:文件沒有數據可讀

B進程:
讀管道,寫文件

B進程結束條件:在寫端關閉,讀端不阻塞,如果管道中沒有數據,讀管道會返回0

linux進程間通信--信號通信