-
Notifications
You must be signed in to change notification settings - Fork 1
Description
它使用 Linux 信号中断在终端中显示剩余时间,并在计时器结束时通知用户。
背景故事:
我使用计时器在长时间阅读和编码活动之间休息。通常,每专注活动 45 分钟,我就会休息 10 到 15 分钟,并使用手机上的计时器应用程序来提醒我休息。但这有一个问题:我必须将目光转向手机,将手从键盘移到手机上,才能查看计时器结束前还剩多少时间。
然后我决定用 Zig 构建一个闹钟应用程序,它可以简单地在我的终端中运行,并在计时器结束时通过弹出窗口和闹钟铃声通知我。
需求和设计:
我的要求是应用程序应以 小时:分钟:秒 的格式显示剩余时间,弹出一个通知,并在计时器结束时响起闹钟铃声。
我一直想在我的应用程序中尝试信号中断,并计划在这个计时器应用程序中使用它们来进行学习和娱乐。
有一个主线程,它接受以秒为单位的计时器值,并休眠相应秒数,然后通知计时器已结束。为了在终端中显示每半秒更新一次的剩余时间,主线程得到了一个子线程的帮助,该子线程通过信号中断每隔半秒通知主线程,以便将剩余时间打印到终端。
实现:
接受计时器值:
应用程序将接受以秒为单位的计时器值,并将其解析为 i64 数字数据类型。随后,解析后的值被转换为 timespec 结构体,该结构体将作为参数传递给 nanosleep,这是一个可中断的休眠函数。
const in_secs = args.next().?;
const timer_secs = try std.fmt.parseInt(i64, in_secs, 10);
var timer_spec: std.os.linux.timespec = .{ .sec = timer_secs, .nsec = 0 };主线程中断器:
如果主线程无限期休眠直到计时器结束,它就无法显示剩余时间。因此,一个子线程将每半秒中断主线程,以便主线程打印剩余时间并恢复计时器。pthread_kill 用于发送中断信号 SIGUSR1。
// 在主线程中调用
_ = try std.Thread.spawn(.{}, remaining_time, .{ init, current_thread });
// 在子线程中运行
const progress_check: std.os.linux.timespec = .{ .sec = 0, .nsec = @divExact(std.time.ns_per_s, 2) };
fn remaining_time(_: std.process.Init, parent_thread: c.pthread_t) !void {
while (true) {
if (std.os.linux.nanosleep(&progress_check, null) != 0) {
std.os.linux.exit(1);
}
_ = c.pthread_kill(parent_thread, c.SIGUSR1);
}
}主线程恢复:
在子线程中断后,主线程中的 nanosleep 返回非零值,指示主线程记录剩余时间。一旦记录了剩余时间,主线程通过使用剩余时间调用 nanosleep 来恢复。当 nanosleep 在没有任何中断的情况下退出(即返回零)时,计时器应用程序以闹钟铃声和通知结束。
while (true) {
if (std.os.linux.nanosleep(&timer_spec, rem_timer_spec) != 0) {
timer_spec = rem_timer_spec.*;
const rem_time = TimeDelta.from_timespec(timer_spec);
_ = try writer.write("\x1b\x5b\x32\x4b\r");
_ = try writer.print("Remaining: {d}Hours, {d}Minutes, {d}Seconds", .{ rem_time.hours, rem_time.minutes, rem_time.seconds });
try writer.flush();
} else {
_ = try writer.print("\nBeep{s}\n", .{&[_]u8{7}});
try writer.flush();
break;
}
}加入我们
Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:
- 供稿,分享自己使用 Zig 的心得
- 改进 ZigCC 组织下的开源项目
- 加入微信群、Telegram 群组