Linux进程编程.docx

上传人:b****1 文档编号:11153810 上传时间:2023-05-29 格式:DOCX 页数:61 大小:45.54KB
下载 相关 举报
Linux进程编程.docx_第1页
第1页 / 共61页
Linux进程编程.docx_第2页
第2页 / 共61页
Linux进程编程.docx_第3页
第3页 / 共61页
Linux进程编程.docx_第4页
第4页 / 共61页
Linux进程编程.docx_第5页
第5页 / 共61页
Linux进程编程.docx_第6页
第6页 / 共61页
Linux进程编程.docx_第7页
第7页 / 共61页
Linux进程编程.docx_第8页
第8页 / 共61页
Linux进程编程.docx_第9页
第9页 / 共61页
Linux进程编程.docx_第10页
第10页 / 共61页
Linux进程编程.docx_第11页
第11页 / 共61页
Linux进程编程.docx_第12页
第12页 / 共61页
Linux进程编程.docx_第13页
第13页 / 共61页
Linux进程编程.docx_第14页
第14页 / 共61页
Linux进程编程.docx_第15页
第15页 / 共61页
Linux进程编程.docx_第16页
第16页 / 共61页
Linux进程编程.docx_第17页
第17页 / 共61页
Linux进程编程.docx_第18页
第18页 / 共61页
Linux进程编程.docx_第19页
第19页 / 共61页
Linux进程编程.docx_第20页
第20页 / 共61页
亲,该文档总共61页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Linux进程编程.docx

《Linux进程编程.docx》由会员分享,可在线阅读,更多相关《Linux进程编程.docx(61页珍藏版)》请在冰点文库上搜索。

Linux进程编程.docx

Linux进程编程

Linux程序设计入门-fork,pthread,andsignals

转自:

Linux技术中坚站

在UNIX程序设计中,学会fork及signal的运用,算是相当基本的功夫。

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\n");

 pid=fork();

 switch(pid){

   case-1:

printf("failure!

\n");break;

   case 0:

printf("Iamchild!

\n");break;

   default:

printf("mychildis%d\n",pid);break;

 }

 for(;;){/*dosomethinghere*/}

}

编译:

gcc-oex1fork.c

执行结果:

./ex1&

hello

mychildis8650

Iamchild!

我们可以见到,使用fork(),可将一个程式分成两个。

在分之前的程序代码只执行一次。

检验行程:

ps|grepex1

 8649 p0R   0:

40./ex1

 8650 p0R   0:

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);

 }

 elseif(pid<0){

   printf("Can'tfork!

\n");

   exit(-1);

 }

 for(;;){

   printf("Iamthedaemon!

\n");

   sleep(3);

   /*dosomethingyourownhere*/

 }

}

编译:

gcc-oex2daemon.c

执行结果:

./ex2

daemononduty!

Iamthedaemon!

接下来每三秒钟,都会出现一个"Iamthedaemon!

"的信息,这表示您的程序已经"长驻"在系统中了。

检验进程:

ps|grepex2

8753 p0S   0:

00./ex2

注意到在范例一中,我们下的指令为"./ex1&",而在范例二中为"./ex2",没有"&"符号。

 

范例三:

lock.c

许多的时候,我们希望"守护神"在系统中只有一个,这时候会需要用到pidlock的技巧。

如果您注意到/var/run目录中的内容,您会发现到有许多的*.pid档,观看其内容都是一些数字,这些数字其实就是该行程的pid。

#include

#include

#include

voidmain(void)

{

 FILE*fp;

 pid_tpid;

 if(access("/var/run/lock.pid",R_OK)==0){

   printf("Existingacopyofthisdaemon!

\n");

   exit

(1);

 }

 pid=fork();

 if(pid>0){

   printf("daemononduty!

\n");

   fp=fopen("/var/run/lock.pid","wt");

   fprintf(fp,"%d",pid);

   fclose(fp);

   exit(0);

 }

 elseif(pid<0){

   printf("Can'tfork!

\n");

   exit(-1);

 }

 

  for(;;){

   printf("Iamthedaemon!

\n");

   sleep(3);

 }

}

编译:

gcc-oex3lock.c

执行:

./ex3

daemononduty!

Iamthedaemon!

再执行一次

./ex3

Existingacopyofthisdaemon!

这时如果您将该行程杀掉,并重新执行:

killallex3

./ex3

Existingacopyofthisdaemon!

您会发现daemon无法再度长驻,因为/var/run/lock.pid并没有因为进程被杀掉而删除掉。

一般来说,开机后的启动Script,会将/var/run中所有内容自动清除,以避免这个问题的发生。

如果您想要在进程被杀掉时,将/var/run/lock.pid也一并删除,那么您需要利用signal来处理这件事。

您可手动删除该档案,daemon便可再度执行。

rm/var/run/lock.pid

范例四:

children.c

如果您正在写伺服器,您可能会需要复制出许多的子进程,用以提供同时多人的服务,这时可利用fork(),一次复制出多个子进程。

最佳的例子为ApacheWWWServer。

#include

#include

#include

#defineMAX_CHILD9

voidmain(void)

{

 pid_tpid;

 int n;

 printf("hello\n");

 n=0;

 do{

   pid=fork();

   n++;

   switch(pid){

     case-1:

       printf("failure!

\n");

       exit(-1);

     break;

     case 0:

       printf("Iamchild%d!

\n",n);

     break;

     default:

       printf("mychildis%d\n",pid);break;

   }

 }while(pid!

=0&&nMAX_CHILD

 if(pid>0)exit(0);

 for(;;){/*dosomethinghere*/}

}

编译:

gcc-oex4children.c

执行结果:

./ex4

hello

mychildis8863

Iamchild1!

mychildis8864

Iamchild2!

mychildis8865

Iamchild3!

mychildis8866

Iamchild4!

mychildis8867

Iamchild5!

mychildis8868

Iamchild6!

mychildis8869

Iamchild7!

mychildis8870

Iamchild8!

mychildis8871

Iamchild9!

检验进程:

ps|grepex4

 8863 p0R   0:

12./ex4

 8864 p0R   0:

12./ex4

 8865 p0R   0:

12./ex4

 8866 p0R   0:

12./ex4

 8867 p0R   0:

12./ex4

 8868 p0R   0:

12./ex4

 8869 p0R   0:

11./ex4

 8870 p0R   0:

12./ex4

 8871 p0R   0:

12./ex4

 

thread

我假设您对thread已经有一些基本的概念,因此,在此我将著重於如何实作。

函数声明

∙int pthread_create(pthread_t * thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg);

∙intpthread_join(pthread_tth,void**thread_return);

∙intpthread_detach(pthread_tth);

∙voidpthread_exit(void*retval);

∙intpthread_attr_init(pthread_attr_t*attr);

资料结构

typedefstruct

{

 intdetachstate;

 intschedpolicy;

 structsched_paramschedparam;

 intinheritsched;

 intscope;

}pthread_attr_t;

范例一:

#include

#include

#include

#include

void*mythread(void*arg)

{

 for(;;){

   printf("thread\n");

   sleep

(1);

 }

 returnNULL;

}

voidmain(void)

{

 pthread_tth;

 if(pthread_create(&th,NULL,mythread,NULL)!

=0)exit(0);

 for(;;){

   printf("mainprocess\n");

   sleep(3);

 }

}

执行结果:

./ex1

mainprocess

thread

thread

thread

mainprocess

thread

thread

thread

mainprocess

thread

thread

thread

mainprocess

信号singals

信号的处理可以用一大章来写,涉及的层面也会深入整个作业系统中,我并不打算这样做,因为您可能会越搞越迷糊。

这里我只告诉您如何接上信号,在实用的层面上,这样便很够用了。

您可以先利用这些基本的技巧来编写程序,等到有进一步高级应用的需要时,找一本较深入的UNIXProgramming教材,专门研究signal的写法。

一般简单的signal写法如下:

voidmysignal(intsigno)

{

 /*mysignalhandler*/

}

voidinitsignal(void)

{

 structsigactionact;

 act.sa_handler=mysignal;

 act.sa_flags  =0;

 sigemptyset(&act.sa_mask);

 sigaction(SIGHUP,&act,NULL);

 sigaction(SIGINT,&act,NULL);

 sigaction(SIGQUIT,&act,NULL);

 sigaction(SIGILL,&act,NULL);

 sigaction(SIGTERM,&act,NULL);

}

 

范例一:

lock.c

在fork的范例三中提到,在daemon被杀掉时,需要在离开前,将/var/run/lock.pid删除。

这里我们可以利用signal来处理这件事。

#include

#include

#include

#include

#defineLOCK_FILE"/var/run/lock.pid"

voidquit(intsigno)

{

 printf("Receivesignal%d\n",signo);

 unlink(LOCK_FILE);

 exit

(1);

}

 

voidmain(void)

{

 FILE*fp;

 pid_tpid;

 structsigactionact;

 if(access(LOCK_FILE,R_OK)==0){

   printf("Existingacopyofthisdaemon!

\n");

   exit

(1);

 }

 pid=fork();

 if(pid>0){

   printf("daemononduty!

\n");

   fp=fopen(LOCK_FILE,"wt");

   fprintf(fp,"%d",pid);

   fclose(fp);

 }else

   exit(0); if(pid<0){

   printf("Can'tfork!

\n");

   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中有各种信号的定义

#defineSIGHUP         1      /*Hangup(POSIX). */

#defineSIGINT         2      /*Interrupt(ANSI). */

#defineSIGQUIT        3      /*Quit(POSIX). */

#defineSIGILL         4      /*Illegalinstruction(ANSI). */

#defineSIGTRAP        5      /*Tracetrap(POSIX). */

#defineSIGABRT        6      /*Abort(ANSI). */

#defineSIGIOT         6      /*IOTtrap(4.2BSD). */

#defineSIGBUS         7      /*BUSerror(4.2BSD). */

#defineSIGFPE         8      /*Floating-pointexception(ANSI). */

#defineSIGKILL        9      /*Kill,unblockable(POSIX). */

#defineSIGUSR1        10     /*User-definedsignal1(POSIX). */

#defineSIGSEGV        11     /*Segmentationviolation(ANSI). */

#defineSIGUSR2        12     /*User-definedsignal2(POSIX). */

#defineSIGPIPE        13     /*Brokenpipe(POSIX). */

#defineSIGALRM        14     /*Alarmclock(POSIX). */

#defineSIGTERM        15     /*Termination(ANSI). */

#defineSIGSTKFLT      16     /*?

?

?

*/

#defineSIGCLD         SIGCHLD/*SameasSIGCHLD(SystemV). */

#defineSIGCHLD        17     /*Childstatushaschanged(POSIX). */

#defineSIGCONT        18     /*Continue(POSIX). */

#defineSIGSTOP        19     /*Stop,unblockable(POSIX). */

#defineSIGTSTP        20     /*Keyboardstop(POSIX). */

#defineSIGTTIN        21     /*Backgroundreadfromtty(POSIX). */

#defineSIGTTOU        22     /*Backgroundwritetotty(POSIX). */

#defineSIGURG         23     /*Urgentconditiononsocket(4.2BSD). */

#defineSIGXCPU        24     /*CPUlimitexceeded(4.2BSD). */

#defineSIGXFSZ        25     /*Filesizelimitexceeded(4.2BSD). */

#defineSIGVTALRM      26     /*Virtualalarmclock(4.2BSD). */

#defineSIGPROF        27     /*Profilingalarmclock(4.2BSD). */

#defineSIGWINCH       28     /*Windowsizechange(4.3BSD,Sun). */

#defineSIGPOLL        SIGIO  /*Pollableeventoccurred(SystemV). */

#defineSIGIO          29     /*I/Onowpossible(4.2BSD). */

#defineSIGPWR         30     /*Powerfailurerestart(SystemV). */

#defineSIGUNUSED      31

函数声明:

SignalOperators

∙intsigemptyset(sigset_t*set);

∙intsigfillset(sigset_t*set);

∙intsigaddset(sigset_t*set,intsignum);

∙intsigdelset(sigset_t*set,intsignum);

∙intsigismember(const

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2