Linux程式设计入门 fork/pthread/signals
时间:2007-02-17 来源:PHP爱好者
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("hellon");
pid=fork();
switch(pid){
case-1:printf("failure!n");break;
case0:printf("Iamchild!n");break;
default:printf("mychildis%dn",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!n");
exit(0);
}else
if(pid<0){
printf("Can'tfork!n");
exit(-1);
}
for(;;){
printf("Iamthedaemon!n");
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);
}
php爱好者站 http://www.phpfans.net 文章|教程|下载|源码|论坛.
虽然在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("hellon");
pid=fork();
switch(pid){
case-1:printf("failure!n");break;
case0:printf("Iamchild!n");break;
default:printf("mychildis%dn",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!n");
exit(0);
}else
if(pid<0){
printf("Can'tfork!n");
exit(-1);
}
for(;;){
printf("Iamthedaemon!n");
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);
}
php爱好者站 http://www.phpfans.net 文章|教程|下载|源码|论坛.
相关阅读 更多 +