Content
0.序
1.基本的同步版本
2.多进程版本
3.多线程版本
4.小结
0.序
本节通过一个简单的闹钟实例演示异步编程方法。
该程序循环接受用户输入信息,直到出错或者输入完毕。用户输入的每行信息有两部分:闹钟等待的时间(秒)和闹钟时间到达时显示的文本信息。
1.基本的同步版本
代码如下。
特点:同步实现异步,闹钟请求后,程序睡眠等待闹钟时间到;
问题:用同步方式来实现异步,致一次只能处理一个闹钟请求;即程序睡眠时间到后才能进行下一次闹钟请求;
运行结果。
2.多进程版本
代码如下。
特点:在子进程中异步地调用sleep函数,而父进程继续运行;
问题:对每次闹钟请求,使用fork创建子进程,程序开销过大;
waitpid()函数
WNOHANG:父进程不必挂起等待子进程的结束;
如果有子进程终止,该函数回收该子进程的资源;
如果没有子进程终止,该函数立即返回pid=0;父进程继续回收终止的子进程直到没有子进程终止;
在每个命令之后循环调用waitpid,来回收所有结束的子进程;
运行结果。
3.多线程版本
代码如下。
特点:在该例子中,alarm线程调用pthread_detach()函数来分离自己,通知pthreads不必关心它的终止时间和退出状态;因此不需要等待线程结束,除非希望获得它的返回值。alarm线程的资源在它终止后立即回收。
一般地,pthreads会保存线程的资源以使其他线程了解它已经终止并获得其最终结果。在本例中,alarm线程负责自己分离自己。
该版本用到以下函数:
pthread_create():创建线程,运行代码由第三个参数指定,运行代码需要的参数由第四个参数传入;返回线程标志符;
Pthread_detach():当线程终止时允许pthreads立即回收线程资源;
pthread_exit():终止调用线程;
运行结果。
4.小结
多进程版本
每个闹钟有一个从主进程拷贝的独立地址空间;
主进程调用waitpid来告诉系统释放其创建的子进程资源;
多线程版本
所有线程共享同一个地址空间;
不需要等待线程结束,除非希望获得它的返回值;
线程间传递消息更快
不需要映射共享内存;
不需要通过管道读写;
不需要担心进程间传送的地址指针是否一致;
线程间共享一切:一个线程内有效的地址指针在所有线程内同样有效;
多线程编程优点
在多处理器系统中开发程序的并行性(仅并行性需要特殊硬件支持);
在等待慢速外设I/O操作结束的同时,程序可以执行其他计算,为程序的并发提供更有效、更自然的开发方式;
一种模块化编程模型,能清晰地表达程序中独立事件间的相互关系;
多线程编程缺点
计算负荷,如线程间同步需要的时间代价;
需要设立较好的编程规则,如要避免死锁、竞争和优先级倒置等;
更难以调试;
何种应用适合使用多线程?
计算密集型应用,为了能在多处理器系统上运行,将这些计算分解到多个线程中实现;
IO密集型应用,为提高性能,将IO操作重叠;如分布式服务器;
Reference
# man waitpid
# man pthread_create
# man pthread_detach