Linux程式設計入門 fork/pthread/signals(轉)

subid發表於2007-08-17
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);

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10796304/viewspace-963408/,如需轉載,請註明出處,否則將追究法律責任。

相關文章