登录
首页 >  文章 >  linux

UNIX 下奇怪的事情

时间:2025-02-18 14:21:49 169浏览 收藏

一分耕耘,一分收获!既然打开了这篇文章《UNIX 下奇怪的事情》,就坚持看下去吧!文中内容包含等等知识点...希望你能在阅读本文后,能真真实实学到知识或者帮你解决心中的疑惑,也欢迎大佬或者新人朋友们多留言评论,多给建议!谢谢!

最近在使用自编工具处理 UNIX 系统任务时,遇到了两个意料之外的情况,并非程序错误,而是行为超出了预期。

UNIX 下奇怪的事情

线程安全 printf 函数
我编写了一个 C 程序,用于读取磁盘上的图像,进行处理,并将结果输出到标准输出 (STDOUT)。简化后的代码如下:
for (imagefilename in images) {
    results = process(imagefilename);
    printf(results);
}

图像处理相互独立,因此我尝试使用 fork() 将处理任务分配到多个 CPU 内核以提高速度:

for (child in children) {
    pipe = create_pipe();
    worker(pipe);
}
// 父进程
for (imagefilename in images) {
    write(pipe[i_image % N_children], imagefilename);
}
worker() {
    while (1) {
        imagefilename = read(pipe);
        results = process(imagefilename);
        printf(results);
    }
}

我创建管道进行进程间通信 (IPC),将文件名发送给子进程 worker。每个 worker 直接写入共享的 STDOUT,导致输出混乱。 flockfile() 函数无法解决问题,因为它受写时复制机制的影响,每个子进程都拥有锁的副本。

我最终选择使用线程而非 fork() 来解决此问题,避免了复杂的管道操作。 代码如下:

for (children) {
    pthread_create(worker, child_index);
}
for (children) {
    pthread_join(child);
}
worker(child_index) {
    for (i_image = child_index; i_image < ... ) {
        // ...
    }
}

这种方法更简洁有效。看来,某些情况下线程比进程更适用。

将部分读取的文件传递给子进程
对于某些 vnlog 工具,我需要实现以下操作序列:
  1. 进程打开一个未设置 O_CLOEXEC 标志的文件。
  2. 进程读取文件的一部分(例如,vnlog 中的图例结尾)。
  3. 进程调用 exec() 执行另一个程序处理已打开文件的剩余部分。

第二个程序可能需要文件名而非文件描述符作为命令行参数,因为它可能自行调用 open()。传递文件名会导致重新打开文件并从头开始读取,这无法满足需求。

我尝试使用 /dev/fd/N 传递文件描述符,但它在 Linux 系统上表现得像符号链接,与传递文件名效果相同。

解决方法是使用管道而非文件。/dev/fd/N 在管道上能正确传递文件描述符。 这可以通过将 open("filename") 替换为 popen("cat filename") 来实现,但这并非理想解决方案。 这在 BSD 系统上的表现可能有所不同。

终于介绍完啦!小伙伴们,这篇关于《UNIX 下奇怪的事情》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>