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

简介:

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

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

相关文章
|
1月前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
3月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第16天】进程、线程和协程是计算机程序执行的三种基本形式。进程是操作系统资源分配和调度的基本单位,具有独立的内存空间,稳定性高但资源消耗大。线程是进程内的执行单元,共享内存,轻量级且并发性好,但同步复杂。协程是用户态的轻量级调度单位,适用于高并发和IO密集型任务,资源消耗最小,但不支持多核并行。
59 1
|
1月前
|
消息中间件 Unix Linux
【C语言】进程和线程详解
在现代操作系统中,进程和线程是实现并发执行的两种主要方式。理解它们的区别和各自的应用场景对于编写高效的并发程序至关重要。
57 6
|
1月前
|
调度 开发者
深入理解:进程与线程的本质差异
在操作系统和计算机编程领域,进程和线程是两个核心概念。它们在程序执行和资源管理中扮演着至关重要的角色。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
58 5
|
29天前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
56 4
|
2月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
2月前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
2月前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
30 1
|
2月前
深入理解操作系统:进程与线程的管理
【10月更文挑战第30天】操作系统是计算机系统的核心,它负责管理计算机硬件资源,为应用程序提供基础服务。本文将深入探讨操作系统中进程和线程的概念、区别以及它们在资源管理中的作用。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程和线程的管理技巧。
46 2