Linux程式設計入門 fork/pthread/signals(轉)
Linux程式設計入門 fork/pthread/signals(轉)[@more@]fork()及signal經常運用在daemon守護神這一類常駐程式,另外像a4c.tty/yact/chdrv這些中文終端機程式也有用到,一般如Mozilla/Apache/Squid等大程式幾乎都一定會用到。
雖然在UNIX下的程式寫作,對thread的功能需求並非很大,但thread在現代的作業系統中,幾乎都已經存在了。pthread是Linux上的thread函式庫,如果您要在Linux下撰寫多執行緒式,例如MP3播放程式,熟悉pthread的用法是必要的。
pthread及signal都可以用一大章來討論。在這裡,我只談及最簡單及常用的技巧,當您熟悉這些基本技巧的運用後,再找一些專門深入探討pthread及signal程式寫作的書籍來研究。這些進階的寫法,用到的機會較少,將層次分明,學習速度應該會比較快。
程式分歧fork()
fork()會產生一個與父程式相同的子程式,唯一不同之處在於其processid(pid)。
如果我們要撰寫守護神程式,或是例如網路伺服器,需要多個行程來同時提供多個連線,可以利用fork()來產生多個相同的行程。
函式宣告
pid_tfork(void);
pid_tvfork(void);
返回值:
-1:失敗。
0:子程式。
>0:將子程式的processid傳回給父程式。
在Linux下fork()及vfork()是相同的東西。
範例一:fork.c
在這個範例中,我們示範fork()的標準用法。
#include
#include
#include
voidmain(void)
{
pid_tpid;
printf("hello ");
pid=fork();
switch(pid){
case-1:printf("failure! ");break;
case0:printf("Iamchild! ");break;
default:printf("mychildis%d ",pid);break;
}
for(;;){/*dosomethinghere*/}
}
編譯:
gcc-oex1fork.c
執行結果:
./ex1&
hello
mychildis8650
Iamchild!
我們可以見到,使用fork(),可將一個程式分岐成兩個。在分歧之前的程式碼只執行一次。
檢驗行程:
ps|grepex1
8649p0R0:40./ex1
8650p0R0:40./ex1
8649是父程式的pid,8650則為子程式的pid。
您會需要用到"killallex1"來殺掉兩個行程。
範例二:daemon.c
在UNIX中,我們一般都利用fork(),來實作所謂的"守護神程式",也就是DOS中所謂的"常駐程式"。一般的技巧是將父程式結束,而子程式便成為"守護神"。
這個範例中,示範一般標準的daemon寫法。
#include
#include
#include
voidmain(void)
{
pid_tpid;
pid=fork();
if(pid>0){
printf("daemononduty! ");
exit(0);
}else
if(pid<0){
printf("Can'tfork! ");
exit(-1);
}
for(;;){
printf("Iamthedaemon! ");
sleep(3);
/*dosomethingyourownhere*/
}
}
編譯:
gcc-oex2daemon.c
執行結果:
./ex2
daemononduty!
Iamthedaemon!
接下來每三秒鐘,都會出現一個"Iamthedaemon!"的訊息,這表示您的程式已經"長駐"在系統中了。
檢驗行程:
ps|grepex2
8753p0S0:00./ex2
注意到在範例一中,我們下的指令為"./ex1&",而在範例二中為"./ex2",沒有"&"符號。
範例三:lock.c
許多的時候,我們希望"守護神"在系統中只有一個,這時候會需要用到pidlock的技巧。如果您注意到/var/run目錄中的內容,您會發現到有許多的*.pid檔,觀看其內容都是一些數字,這些數字其實就是該行程的pid。
#include
#include
#include
voidmain(void)
{
FILE*fp;
pid_tpid;
exit(-1);
}
act.sa_handler=quit;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
for(;;){
sleep(3);
}
}
編譯:
gcc-oex1lock.c
執行
./ex1
daemononduty!
送訊號
我們先找出該守護神程式的pid
PID=`cat/var/run/lock.pid`
接下來利用kill來送訊號
kill$PID
Receivesignal15
程式將會結束,並且/var/run/lock.pid將會被刪除掉,以便下一次daemon再啟動。注意到如果quit函式內,沒有放exit(),程式將永遠殺不掉。
接下來送一些其它的訊號試試看。
./ex1
PID=`cat/var/run/lock.pid`
kill-HUP$PID
Receivesignal1
您可以自行試試
kill-INT$PID
kill-QUIT$PID
kill-ILL$PID
.
.
.
等等這些訊號,看看他們的結果如何。
訊號的定義
在/usr/include/signum.h中有各種訊號的定義
#defineSIGHUP1/*Hangup(POSIX).*/
#defineSIGINT2/*Interrupt(ANSI).*/
#defineSIGQUIT3/*Quit(POSIX).*/
#defineSIGILL4/*Illegalinstruction(ANSI).*/
#defineSIGTRAP5/*Tracetrap(POSIX).*/
#defineSIGABRT6/*Abort(ANSI).*/
#defineSIGIOT6/*IOTtrap(4.2BSD).*/
#defineSIGBUS7/*BUSerror(4.2BSD).*/
#defineSIGFPE8/*Floating-pointexception(ANSI).
*/
#defineSIGKILL9/*Kill,unblockable(POSIX).*/
#defineSIGUSR110/*User-definedsignal1(POSIX).*/
#defineSIGSEGV11/*Segmentationviolation(ANSI).*/
#defineSIGUSR212/*User-definedsignal2(POSIX).*/
#defineSIGPIPE13/*Brokenpipe(POSIX).*/
#defineSIGALRM14/*Alarmclock(POSIX).*/
#defineSIGTERM15/*Termination(ANSI).*/
#defineSIGSTKFLT16/*???*/
#defineSIGCLDSIGCHLD/*SameasSIGCHLD(SystemV).*/
#defineSIGCHLD17/*Childstatushaschanged(POSIX).
*/
#defineSIGCONT18/*Continue(POSIX).*/
#defineSIGSTOP19/*Stop,unblockable(POSIX).*/
#defineSIGTSTP20/*Keyboardstop(POSIX).*/
#defineSIGTTIN21/*Backgroundreadfromtty(POSIX).
*/
#defineSIGTTOU22/*Backgroundwritetotty(POSIX).
*/
#defineSIGURG23/*Urgentconditiononsocket(4.2
BSD).*/
#defineSIGXCPU24/*CPUlimitexceeded(4.2BSD).*/
#defineSIGXFSZ25/*Filesizelimitexceeded(4.2
BSD).*/
#defineSIGVTALRM26/*Virtualalarmclock(4.2BSD).*/
#defineSIGPROF27/*Profilingalarmclock(4.2BSD).
*/
#defineSIGWINCH28/*Windowsizechange(4.3BSD,Sun).
*/
#defineSIGPOLLSIGIO/*Pollableeventoccurred(System
V).*/
#defineSIGIO29/*I/Onowpossible(4.2BSD).*/
#defineSIGPWR30/*Powerfailurerestart(SystemV).
*/
#defineSIGUNUSED31
函式宣告:
SignalOperators
intsigemptyset(sigset_t*set);
intsigfillset(sigset_t*set);
intsigaddset(sigset_t*set,intsignum);
intsigdelset(sigset_t*set,intsignum);
intsigismember(constsigset_t*set,intsignum);
SignalHandlingFunctions
intsigaction(intsignum,conststructsigaction*act,struct
sigaction*oldact);
intsigprocmask(inthow,constsigset_t*set,sigset_t
*oldset);
intsigpending(sigset_t*set);
intsigsuspend(constsigset_t*mask);
StructureSignalAction
structsigaction{
void(*sa_handler)(int);
sigset_tsa_mask;
intsa_flags;
void(*sa_restorer)(void);
}
雖然在UNIX下的程式寫作,對thread的功能需求並非很大,但thread在現代的作業系統中,幾乎都已經存在了。pthread是Linux上的thread函式庫,如果您要在Linux下撰寫多執行緒式,例如MP3播放程式,熟悉pthread的用法是必要的。
pthread及signal都可以用一大章來討論。在這裡,我只談及最簡單及常用的技巧,當您熟悉這些基本技巧的運用後,再找一些專門深入探討pthread及signal程式寫作的書籍來研究。這些進階的寫法,用到的機會較少,將層次分明,學習速度應該會比較快。
程式分歧fork()
fork()會產生一個與父程式相同的子程式,唯一不同之處在於其processid(pid)。
如果我們要撰寫守護神程式,或是例如網路伺服器,需要多個行程來同時提供多個連線,可以利用fork()來產生多個相同的行程。
函式宣告
pid_tfork(void);
pid_tvfork(void);
返回值:
-1:失敗。
0:子程式。
>0:將子程式的processid傳回給父程式。
在Linux下fork()及vfork()是相同的東西。
範例一:fork.c
在這個範例中,我們示範fork()的標準用法。
#include
#include
#include
voidmain(void)
{
pid_tpid;
printf("hello ");
pid=fork();
switch(pid){
case-1:printf("failure! ");break;
case0:printf("Iamchild! ");break;
default:printf("mychildis%d ",pid);break;
}
for(;;){/*dosomethinghere*/}
}
編譯:
gcc-oex1fork.c
執行結果:
./ex1&
hello
mychildis8650
Iamchild!
我們可以見到,使用fork(),可將一個程式分岐成兩個。在分歧之前的程式碼只執行一次。
檢驗行程:
ps|grepex1
8649p0R0:40./ex1
8650p0R0:40./ex1
8649是父程式的pid,8650則為子程式的pid。
您會需要用到"killallex1"來殺掉兩個行程。
範例二:daemon.c
在UNIX中,我們一般都利用fork(),來實作所謂的"守護神程式",也就是DOS中所謂的"常駐程式"。一般的技巧是將父程式結束,而子程式便成為"守護神"。
這個範例中,示範一般標準的daemon寫法。
#include
#include
#include
voidmain(void)
{
pid_tpid;
pid=fork();
if(pid>0){
printf("daemononduty! ");
exit(0);
}else
if(pid<0){
printf("Can'tfork! ");
exit(-1);
}
for(;;){
printf("Iamthedaemon! ");
sleep(3);
/*dosomethingyourownhere*/
}
}
編譯:
gcc-oex2daemon.c
執行結果:
./ex2
daemononduty!
Iamthedaemon!
接下來每三秒鐘,都會出現一個"Iamthedaemon!"的訊息,這表示您的程式已經"長駐"在系統中了。
檢驗行程:
ps|grepex2
8753p0S0:00./ex2
注意到在範例一中,我們下的指令為"./ex1&",而在範例二中為"./ex2",沒有"&"符號。
範例三:lock.c
許多的時候,我們希望"守護神"在系統中只有一個,這時候會需要用到pidlock的技巧。如果您注意到/var/run目錄中的內容,您會發現到有許多的*.pid檔,觀看其內容都是一些數字,這些數字其實就是該行程的pid。
#include
#include
#include
voidmain(void)
{
FILE*fp;
pid_tpid;
exit(-1);
}
act.sa_handler=quit;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
for(;;){
sleep(3);
}
}
編譯:
gcc-oex1lock.c
執行
./ex1
daemononduty!
送訊號
我們先找出該守護神程式的pid
PID=`cat/var/run/lock.pid`
接下來利用kill來送訊號
kill$PID
Receivesignal15
程式將會結束,並且/var/run/lock.pid將會被刪除掉,以便下一次daemon再啟動。注意到如果quit函式內,沒有放exit(),程式將永遠殺不掉。
接下來送一些其它的訊號試試看。
./ex1
PID=`cat/var/run/lock.pid`
kill-HUP$PID
Receivesignal1
您可以自行試試
kill-INT$PID
kill-QUIT$PID
kill-ILL$PID
.
.
.
等等這些訊號,看看他們的結果如何。
訊號的定義
在/usr/include/signum.h中有各種訊號的定義
#defineSIGHUP1/*Hangup(POSIX).*/
#defineSIGINT2/*Interrupt(ANSI).*/
#defineSIGQUIT3/*Quit(POSIX).*/
#defineSIGILL4/*Illegalinstruction(ANSI).*/
#defineSIGTRAP5/*Tracetrap(POSIX).*/
#defineSIGABRT6/*Abort(ANSI).*/
#defineSIGIOT6/*IOTtrap(4.2BSD).*/
#defineSIGBUS7/*BUSerror(4.2BSD).*/
#defineSIGFPE8/*Floating-pointexception(ANSI).
*/
#defineSIGKILL9/*Kill,unblockable(POSIX).*/
#defineSIGUSR110/*User-definedsignal1(POSIX).*/
#defineSIGSEGV11/*Segmentationviolation(ANSI).*/
#defineSIGUSR212/*User-definedsignal2(POSIX).*/
#defineSIGPIPE13/*Brokenpipe(POSIX).*/
#defineSIGALRM14/*Alarmclock(POSIX).*/
#defineSIGTERM15/*Termination(ANSI).*/
#defineSIGSTKFLT16/*???*/
#defineSIGCLDSIGCHLD/*SameasSIGCHLD(SystemV).*/
#defineSIGCHLD17/*Childstatushaschanged(POSIX).
*/
#defineSIGCONT18/*Continue(POSIX).*/
#defineSIGSTOP19/*Stop,unblockable(POSIX).*/
#defineSIGTSTP20/*Keyboardstop(POSIX).*/
#defineSIGTTIN21/*Backgroundreadfromtty(POSIX).
*/
#defineSIGTTOU22/*Backgroundwritetotty(POSIX).
*/
#defineSIGURG23/*Urgentconditiononsocket(4.2
BSD).*/
#defineSIGXCPU24/*CPUlimitexceeded(4.2BSD).*/
#defineSIGXFSZ25/*Filesizelimitexceeded(4.2
BSD).*/
#defineSIGVTALRM26/*Virtualalarmclock(4.2BSD).*/
#defineSIGPROF27/*Profilingalarmclock(4.2BSD).
*/
#defineSIGWINCH28/*Windowsizechange(4.3BSD,Sun).
*/
#defineSIGPOLLSIGIO/*Pollableeventoccurred(System
V).*/
#defineSIGIO29/*I/Onowpossible(4.2BSD).*/
#defineSIGPWR30/*Powerfailurerestart(SystemV).
*/
#defineSIGUNUSED31
函式宣告:
SignalOperators
intsigemptyset(sigset_t*set);
intsigfillset(sigset_t*set);
intsigaddset(sigset_t*set,intsignum);
intsigdelset(sigset_t*set,intsignum);
intsigismember(constsigset_t*set,intsignum);
SignalHandlingFunctions
intsigaction(intsignum,conststructsigaction*act,struct
sigaction*oldact);
intsigprocmask(inthow,constsigset_t*set,sigset_t
*oldset);
intsigpending(sigset_t*set);
intsigsuspend(constsigset_t*mask);
StructureSignalAction
structsigaction{
void(*sa_handler)(int);
sigset_tsa_mask;
intsa_flags;
void(*sa_restorer)(void);
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10796304/viewspace-963408/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- pthread 入門thread
- 【Linux】Linux系統程式設計入門Linux程式設計
- Linux入門---(三)Shell程式設計Linux程式設計
- Linux系統程式設計入門Linux程式設計
- Linux-shell程式設計入門基礎Linux程式設計
- Linux 利器- Python 指令碼程式設計入門(一)LinuxPython指令碼程式設計
- 入門程式碼程式設計程式設計
- Linux Socket C語言網路程式設計:Pthread Socket [code from GitHub, for study]LinuxC語言程式設計threadGithub
- Linux fork程式的用法Linux
- Shell 程式設計入門程式設計
- Python程式設計入門Python程式設計
- 程式設計和網路程式設計入門程式設計
- Number 1 — 程式設計入門程式設計
- Flink DataStream 程式設計入門AST程式設計
- java Swing程式設計入門Java程式設計
- Linux命令列與shell指令碼程式設計入門經驗Linux命令列指令碼程式設計
- JavaScript 非同步程式設計入門JavaScript非同步程式設計
- 程式設計入門學什麼?程式設計
- 遊戲程式設計入門指南遊戲程式設計
- Python 非同步程式設計入門Python非同步程式設計
- JAVA NIO程式設計入門(二)Java程式設計
- JAVA NIO 程式設計入門(三)Java程式設計
- JAVA NIO程式設計入門(一)Java程式設計
- 程式設計正規化 —— 函數語言程式設計入門程式設計函數
- 14.1 Socket 套接字程式設計入門程式設計
- Go語言程式設計快速入門Go程式設計
- Java入門之基礎程式設計Java程式設計
- 程式設計入門先學什麼?程式設計
- iOS 逆向程式設計(入門條件)iOS程式設計
- SDL程式設計入門(26)運動程式設計
- 響應式程式設計入門(RxJava)程式設計RxJava
- 普通人轉行程式設計師之自學java入門篇行程程式設計師Java
- 程式設計師有哪些發展方向?linux運維入門學習程式設計師Linux運維
- 程式設計師程式設計入門一定知道!程式設計師需要學什麼?程式設計師
- 程式設計入門,這763位老程式設計師有話講!程式設計師
- 新手程式設計入門先學什麼?程式設計
- 程式設計入門之日誌聚合系統程式設計
- Go Web 程式設計入門--路由器GoWeb程式設計路由器
- Go Web 程式設計入門--應用 ORMGoWeb程式設計ORM