Skip to content

【Zig 日报】一个用 Zig 编写的简单计时器应用程序 #304

@jiacai2050

Description

@jiacai2050

它使用 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;
    }
}

Learning Linux signal interrupts from building a timer

加入我们

Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:

  1. 供稿,分享自己使用 Zig 的心得
  2. 改进 ZigCC 组织下的开源项目
  3. 加入微信群Telegram 群组

Metadata

Metadata

Assignees

No one assigned

    Labels

    日报daily report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions