Linux-程序通訊-管道/訊號
pipe
無名管道,只能用於親緣關係的程序間通訊,半雙工,固定讀fd[0],寫fd[1],檔案I/O實現;
當管道中午資料時,讀阻塞;
當寫緩衝區滿時又不被讀走,此時寫阻塞;
例項:父程序讀阻塞,子程序寫成功然後父程序讀成功返回。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define MAX 1024 int main() { int fd[2]; int ret = pipe(fd); if(0 > ret) { perror("pipe"); exit(-1); } pid_t pid = fork(); if(0 > pid) { perror("fork"); exit(-1); } if(0 == pid) { printf("child process\n"); sleep(3); char buf[] = "hello world"; ret = write(fd[1], buf, sizeof(buf)-1); if(0 > ret) { perror("write"); exit(-1); } } if(0 < pid) { char rbuf[MAX]; memset(rbuf, 0, MAX); printf("parent process\n"); ret = read(fd[0], rbuf, MAX); if(0 > ret) { perror("read"); exit(-1); } printf("read num:%d,buf:%s\n", ret, rbuf); } exit(0); }
fifo
有名管道,可實現不相干的程序間通訊,檔案I/O操作。
讀寫阻塞通過O_NONBLOCK控制,表示非阻塞,下面例子是寫非阻塞,讀阻塞;先執行讀程序(被阻塞),再執行寫程序,一切正常;若先執行寫程序,open呼叫將返回-1,開啟失敗。
#define FIFONAME "/tmp/myfifo" mkfifo(FIFONAME, O_CREAT) int fd = open(FIFONAME, O_WRONLY|O_NONBLOCK, 0); char buf[] = "hello FIFO test."; write(fd, buf, sizeof(buf) char buf_r[100]; memset(buf_r,0,sizeof(buf_r)); int fd = open(FIFONAME, O_RDONLY, 0); read(fd,buf_r, 100) unlink(FIFONAME)
訊號通訊 kill/raise
中斷控制,非同步通訊方式,軟中斷核心控制;
kill把訊號傳送給程序或程序組;int kill(pid_t pid, int signo);成功則返回0, 出錯則返回-1;
raise把訊號傳送給(程序)自身;int raise(int signo);成功則返回0, 出錯則返回-1。
kill(getppid(), SIGKILL);殺死父程序;
raise(SIGKILL);殺死自己程序;
wait函式
wait函式阻塞自己程序,直到自己的某一個子程序退出函式才返回;
pid_t wait(int *status),status儲存子程序退出時的一些狀態,返回子程序的id,
pid_t waitpid(pid_t pid, int *status, int options),pid>0時,只等待程序ID等於pid的子程序;pid=-1時,等待任何一個子程序退出;pid=0時,等待同一個程序組中的任何子程序;pid<-1時,等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值。
alarm函式
alarm函式設定一個定時器,時間到後向當前程序傳送一個SIGALARM終止訊號;如果alarm()前已經設定了一個鬧鐘,可以呼叫alarm(0)來取消此鬧鐘,並返回剩餘時間;如果想重新設定一個鬧鐘,可以alarm(n),會取消前的鬧鐘並返回剩餘時間,然後重新開始倒計時。
pause函式
pause函式使程序或執行緒進入睡眠狀態,直到收到訊號。
signal函式
註冊訊號處理函式,函式原型:sighandler_t signal(int signum, sighandler_t handler);
signum是我們要處理的訊號,系統訊號可通過命令kill -l檢視:
handler是收到訊號後的處理動作,SIG_ING是收到訊號後忽略,比如signal(SIGINT, SIG_IGN);收到中斷訊號忽略,那麼用Ctrl+C就不能中斷程式,此時可用Ctrl+\傳送Quit訊號;
handler還可以是函式,收到訊號後執行函式,如下面的例子:收到訊號後就去執行handler函式,執行完後前面的函式繼續執行。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#define _GNU_SOURCE
#define MAX 9
char arr[MAX];
void unrecall(int val)
{
for(int i = 0; i < MAX; i++)
{
arr[i] = val+i;
printf("NO %d.%d: %d\n",val, i, arr[i]);
sleep(1);
}
}
void handler(int sig)
{
unrecall(sig);
}
int main()
{
if(SIG_ERR == signal(SIGUSR1, handler))
perror("signal");
pid_t pid = fork();
if(0 > pid)
{
perror("fork");
exit(-1);
}
else if(0 == pid)
{
sleep(5);
kill(getppid(), SIGUSR1);
}
else if(0 < pid)
{
printf("SIGUSR1=%d\n", SIGUSR1);//10
unrecall(1);
for(int i = 0; i < MAX; i++)
{
printf("all:NO.%d: %d\n", i, arr[i]);
}
}
exit(0);
}
傳送訊號可用kill和raise函式。