且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

一个定时器的普通实现,多进程实现和多线程实现的对比

更新时间:2022-08-22 17:10:40

要求实现一个简单的定时器,该程序要求的输入格式为:

N prompt message

其中N表示时间,prompt message表示提示信息。即过了N秒之后要在终端上显示出提示信息。一共用了三种方式实现:(1)最普通的方式,阻塞I/0+同步。(2)使用进程实现。(3)使用线程实现。

 


  1. /*alarm.c*/ 
  2.  
  3. #include "../error.h" 
  4.  
  5. #include<time.h> 
  6.  
  7. int main(int argc,char *argv[]) 
  8.  
  9.  
  10.         int seconds; 
  11.  
  12.         char line[128]; 
  13.  
  14.         char message[64]; 
  15.  
  16.         while(NULL != fgets(line,sizeof(line),stdin)) 
  17.  
  18.         { 
  19.  
  20.                 if( 2 > sscanf(line,"%d %64[^\n]",&seconds,message)) 
  21.  
  22.                         fprintf(stderr,"Bad Command\n"); 
  23.  
  24.                 else 
  25.  
  26.                 { 
  27.  
  28.                         sleep(seconds); 
  29.  
  30.                         fprintf(stdout,"%s\n",message); 
  31.  
  32.                 } 
  33.  
  34.         } 
  35.  
  36.         return 0; 
  37.  

评注:

1.常量和函数比较的时候,将常量放在前面可以防止将==写成=,因为编译器会报错。

2.sscanf为从一个字符缓冲区中格式化读取数据。注意字符缓冲区放在第一个参数位置。使用%N可以控制读取字符的数量,中括号的作用和正则表达式中的作用一样,将不读取的字符排除掉或者仅读取中括号内指定的字符集,成功时,返回读取的参数的个数。

3.使用fgets+sscanf,简化了从命令行中提取参数问题。

3.fgets从指定的文件描述符中读取一行字符串,失败时返回NULL

4.对于每个函数都添加了判断语句,特别有助于调试。


  1. /*alarm_fork.c*/ 
  2.  
  3. #include "../error.h" 
  4.  
  5. #include <sys/types.h> 
  6.  
  7. #include<wait.h> 
  8.  
  9.   
  10.  
  11. int main(int argc,char *argv[]) 
  12.  
  13.  
  14.         pid_t pid; 
  15.  
  16.         int seconds; 
  17.  
  18.         char line[128]; 
  19.  
  20.         char message[64]; 
  21.  
  22.         while(NULL != fgets(line,sizeof(line),stdin)) 
  23.  
  24.         { 
  25.  
  26.                 if(2 > sscanf(line,"%d %64[^\n]",&seconds,message)) 
  27.  
  28.                 { 
  29.  
  30.                         fprintf(stdout,"Bad command.\n"); 
  31.  
  32.                         continue
  33.  
  34.                 } 
  35.  
  36.                 else 
  37.  
  38.                 { 
  39.  
  40.                         pid = fork(); 
  41.  
  42.                         if((pid_t)-1 == pid) 
  43.  
  44.                         { 
  45.  
  46.                                 error_abort("fork error..."); 
  47.  
  48.                         } 
  49.  
  50.                         else if((pid_t)0 == pid) 
  51.  
  52.                         { 
  53.  
  54.                                 sleep(seconds); 
  55.  
  56.                                 fprintf(stdout,"%s\n",message); 
  57.  
  58.                                 exit(0); 
  59.  
  60.                         } 
  61.  
  62.                         else 
  63.  
  64.                         { 
  65.  
  66.                                 do 
  67.  
  68.                                 { 
  69.  
  70.                                         pid = waitpid((pid_t)-1,NULL,WNOHANG); 
  71.  
  72.                                         if((pid_t)-1 == pid) 
  73.  
  74.                                         { 
  75.  
  76.                                                 error_abort("waitpid error..."); 
  77.  
  78.                                         } 
  79.  
  80.                                 }while((pid_t)0 != pid); 
  81.  
  82.   
  83.  
  84.                         } 
  85.  
  86.                 } 
  87.  
  88.         } 
  89.  
  90.         return 0; 
  91.  

1.pid_t这个类型在sys/types.h头文件中。

2.比较的时候要进行强制类型转换,比如判断进程id是不是为0,就要使用(pid_t)0 == pid这样的判断语句。

3.waitpid的第一个参数设置为-1,第三个参数设置为WNOHANG,表示非阻塞等待任何一个子进程。如果发现一个子进程返回,立即再判断是否还有其他进程返回。可以迅速的释放不再使用的资源。

 


  1. /*alarm_thread.c*/ 
  2.  
  3. #include "../error.h" 
  4.  
  5. #include <sys/types.h> 
  6.  
  7. #include <pthread.h> 
  8.  
  9. #include <time.h> 
  10.  
  11.   
  12.  
  13. typedef struct alarm_tag 
  14.  
  15.  
  16.         int seconds; 
  17.  
  18.         char message[64]; 
  19.  
  20. }alarm_t,*alarm_p; 
  21.  
  22.   
  23.  
  24. void * alarm_thread(void * arg) 
  25.  
  26.  
  27.         int status; 
  28.  
  29.         status = pthread_detach(pthread_self()); 
  30.  
  31.         if(0 != status) 
  32.  
  33.                 err_abort("detaching thread failure...",status); 
  34.  
  35.         alarm_p alarm = (alarm_p) arg; 
  36.  
  37.         sleep(alarm->seconds); 
  38.  
  39.         fprintf(stdout,"%s\n",alarm->message); 
  40.  
  41.  
  42.   
  43.  
  44. int main(int argc,char *argv[]) 
  45.  
  46.  
  47.         pthread_t thread
  48.  
  49.         char line[128]; 
  50.  
  51.         alarm_p alarm; 
  52.  
  53.         int status; 
  54.  
  55.         while(NULL != fgets(line,sizeof(line),stdin)) 
  56.  
  57.         { 
  58.  
  59.                 alarm = (alarm_p) malloc(sizeof(alarm_t)); 
  60.  
  61.                 if( NULL == alarm) 
  62.  
  63.                         error_abort("Allocating alarm failure..."); 
  64.  
  65.                 if(2 > sscanf(line,"%d %64[^\n]",&alarm->seconds,alarm->message)) 
  66.  
  67.                 { 
  68.  
  69.                         fprintf(stdout,"%s\n","Bad command"); 
  70.  
  71.                         free(alarm); 
  72.  
  73.                         continue
  74.  
  75.                 } 
  76.  
  77.                 else 
  78.  
  79.                 { 
  80.  
  81.                         status = pthread_create(&thread,NULL,alarm_thread,(void *)alarm); 
  82.  
  83.                         if(0 != status) 
  84.  
  85.                                 err_abort("creating thread failure...",status); 
  86.  
  87.                 } 
  88.  
  89.         } 
  90.  
  91.         return 0; 
  92.  

1.Pthreads相关的类型,接口原型,常量都在pthread.h这个头文件中,编译的时候要加 -lpthread.

2.由于线程的参数只有一个,所以要将传给线程的所有参数封装到一个结构体中。

 

使用普通方式,多进程,多线程的比较

alarm一次只能发出一个定时请求。如果发出一个10分钟的请求,那么必须要等十分钟才能发出下一个请求。多进程解决了这个同步问题,但是在一个系统中,一个用户能够启动的进程的数量是非常有限的,多线程受到这个影响要小得多。

 

多线程的几个好处

1)发掘多核计算潜力

2)发掘程序自身的并发性

3)模块式的编程模型,可以更加清晰的表达不同事件之间的关系



本文转自hipercomer 51CTO博客,原文链接:http://blog.51cto.com/hipercomer/908959