前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >异步编程举例之多线程版本闹钟

异步编程举例之多线程版本闹钟

作者头像
用户5908113
发布2019-07-30 15:37:22
7190
发布2019-07-30 15:37:22
举报
文章被收录于专栏:Pou光明

现在让我们看一个和多进程版本相似的闹钟程序,但它是用多线程实现的。该例子中用到的三个Pthreads函数:

●pthread_create : 创建一个线程,运行由第三个参数(alarm_thread)指定的例程(具体见下面例子),并返回线程标识符ID(保存在thread引用的变量中)

● pthread_detach : 当线程终止时立刻回收线程资源

● pthread_exit: 终止线程调用

数据结构alarm_t中定义了每个闹钟的命令信息,seconds中存储等待时间,message中存储显示文本。

#include <pthread.h>

#include "errors.h"

typedef struct alarm_tag {

int seconds;

char message[64];

} alarm_t;

函数alarm_thread是闹钟线程,即创建的每个闹钟线程执行的函数,该函数返回时,闹钟线程终止。该函数参数(void *arg)是传给pthread_create函数的第四个参数,即alarm_t结构体指针。线程首先将void* 参数转为alarm_t* 类型,然后调用pthread_detach函数来分离自己,作用是通知Pthreads不必关心它的终止时间与退出状态。

线程睡眠指定的时间(由alarm_t 中的seconds决定),之后打印指定的消息文本,最后释放alarm_t结构体空间并返回,线程终止。通常,Pthreads会保存线程的资源以供其他线程了解它已经终止并获得其最终结果。由于本例中线程负责分离自己,所以不必做上述工作。

void *alarm_thread (void *arg)

{

alarm_t *alarm = (alarm_t*)arg;

int status;

status = pthread_detach (pthread_self ());

if (status != 0)

err_abort (status, "Detach thread");

sleep (alarm->seconds);

printf ("(%d) %s\n", alarm->seconds, alarm->message);

free (alarm);

return NULL;

}

线程版本闹钟的main()函数与之前的两个版本相同,循环读取命令行、解析命令行直到不能从stdin中读取数据为止。

创建一个闹钟线程,它以alarm_t为线程参数运行函数alarm_thread。

int main()

{

int status;

char line[128];

alarm_t *alarm;

pthread_t thread;

while (1) {

printf ("Alarm> ");

if (fgets (line, sizeof (line), stdin) == NULL) exit (0);

if (strlen (line) <= 1) continue;

alarm = (alarm_t*)malloc (sizeof (alarm_t));

if (alarm == NULL)

errno_abort ("Allocate alarm");

if (sscanf (line, "%d %64[^\n]",

&alarm->seconds, alarm->message) < 2) {

fprintf (stderr, "Bad command\n");

free (alarm);

} else {

status = pthread_create (

&thread, NULL, alarm_thread, alarm);

if (status != 0)

err_abort (status, "Create alarm thread");

}

}

}

总结:比较两个异步版本闹钟程序是理解线程编程很好的选择。在fork版本中,每个闹钟有一个从主进程拷贝的独立地址空间,这意味着可以将闹钟时间和显示文本放在局部变量中,一旦创建了子进程,父进程就可以改变这些变量而不会影响闹钟子进程。在多线程版本中,所有线程共享同一个地址空间,所以可为每个闹钟调用malloc建立新的alarm_t结构体,并传递给新建线程。

在使用fork()版本中,主进程要调用waitpid函数来通知系统释放其创建的子进程资源。在多线程版本中,不需要等待线程结束,除非希望获得它的返回值;每个线程分离自己,故该线程的资源在它终止后会立刻回收。

在实际应用中,不会为每个闹钟建立一个进程。你可能轻易设置上百个闹钟活动,但是系统可能无法创建那么多进程。但是对应可以在一个进程中创建几百个线程。

另外可以将常用的头文件以及一些宏定义包含在一个头文件中,比如#include "errors.h"。本次程序的运行环境依然是Qt的控制台程序。

彩蛋:一个更加成熟的闹钟版本可以只有两个线程:一个负责读取用户输入,一个等待闹钟停止。之后的学习会逐步实现该版本。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Pou光明 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档