【问题标题】:Forking vs Threading分叉与线程
【发布时间】:2013-04-27 14:15:54
【问题描述】:

我以前在我的应用程序中使用过线程并且非常了解它的概念,但是最近在我的操作系统讲座中我遇到了 fork()。这类似于线程。

我用谷歌搜索了它们之间的区别,我知道了:

  1. Fork 只是一个新进程,看起来与旧进程或父进程完全一样,但它仍然是具有不同进程 ID 并拥有自己内存的不同进程。
  2. 线程是开销较小的轻量级进程

但是,我心中仍有一些疑问。

  1. 什么时候你应该更喜欢 fork() 而不是线程,反之亦然?
  2. 如果我想在小时候调用外部应用程序,我应该使用 fork() 还是线程来执行它?
  3. 在进行谷歌搜索时,我发现有人说在线程中调用 fork() 是一件坏事。为什么人们在做类似的事情时要在线程内调用 fork()?
  4. fork() 确实不能利用多处理器系统,因为父进程和子进程不同时运行吗?

【问题讨论】:

    标签: linux multithreading unix programming-languages fork


    【解决方案1】:

    分叉和线程方法的主要区别在于操作系统架构之一。早在设计 Unix 的时候,fork 是一个简单的系统,可以最好地满足大型机和服务器类型的要求,因此它在 Unix 系统上得到了普及。当微软从头开始重新构建 NT 内核时,它更多地关注线程模型。因此,今天仍然存在显着差异,Unix 系统在 fork 上的效率更高,而 Windows 在线程上的效率更高。您可以在 Apache 中最明显地看到这一点,它在 Unix 上使用 prefork 策略,在 Windows 上使用线程池。

    特别针对您的问题:

    什么时候你应该更喜欢 fork() 而不是线程,反之亦然?

    在 Unix 系统上,您执行的任务远比仅仅实例化一个 worker 复杂得多,或者您想要单独进程的隐式安全沙盒。

    如果我想在小时候调用外部应用程序,那么我应该使用 fork() 还是线程来做呢?

    如果孩子将使用相同的代码执行与父母相同的任务,请使用 fork。对于较小的子任务,使用线程。对于单独的外部进程,两者都不使用,只需使用适当的 API 调用来调用它们。

    在进行谷歌搜索时,我发现有人说在线程中调用 fork() 是一件坏事。为什么人们在做类似的事情时要在线程内调用 fork()?

    不完全确定,但我认为复制一个进程和大量子线程在计算上相当昂贵。

    由于父进程和子进程不同时运行,fork() 不能利用多处理器系统,这是真的吗?

    这是错误的,fork 会创建一个新进程,然后该进程会利用操作系统任务调度程序中进程可用的所有功能。

    【讨论】:

    • 在 Unix 上,调用外部程序的正确 API 是 fork,然后是 exec(我在这里省略了许多其他细节)。对于一些特殊情况,还有更简单的替代方案(主要是popen)。
    • fork() 只复制调用线程。它并不昂贵,因为fork() 使用 COW。当您还想使用 fork() 而不直接跟随 exec*() 时使用线程通常是一个坏主意,因为当其他线程突然停止时,其他线程可能持有无法在子进程中释放的锁。
    【解决方案2】:

    分叉的进程称为重量级进程,而线程化的进程称为轻量级进程。

    以下是它们之间的区别:

    1. 派生的进程被视为子进程,而线程化的进程称为兄弟进程。
    2. 分叉进程不与父进程共享代码、数据、堆栈等资源,而线程进程可以共享代码但有自己的堆栈。
    3. 进程切换需要操作系统的帮助,但线程切换不是必需的
    4. 创建多个进程是一项资源密集型任务,而创建多个线程是一项资源密集型任务
    5. 每个进程可以独立运行,而一个线程可以读取/写入另一个线程数据。 线程和进程lecture

    【讨论】:

    • 我不认为它是如何在不问一些问题的情况下获得大量选票的。 1)一个分叉的进程被认为是一个子进程,而一个线程进程被称为兄弟进程。——这一点是无关紧要的,机器不关心你是孩子还是同胞。 2)进程切换需要操作系统的帮助,但线程切换不是必需的——它确实如此,除非您使用称为用户级线程的东西。 3)创建多个进程是一项资源密集型任务,而创建多个线程是资源密集型任务 - 取决于实现。
    • 在 Linux 和许多其他系统上,进程并不比进程重。多亏了 COW,代码以及大部分堆和堆栈在子级和父级之间共享。一个分叉的进程可以与父进程共享东西,例如一个进程可以请求将与未来的子进程共享的内存。
    【解决方案3】:

    fork() 会生成一个新的进程副本,正如您所指出的。上面没有提到的是经常跟随的exec() 调用。这会用新进程(新的可执行文件)替换现有进程,因此,fork()/exec() 是从旧进程生成新进程的标准方法。

    例如这就是您的 shell 从命令行调用进程的方式。您指定您的进程(例如ls)和shell fork,然后执行ls

    请注意,这在与线程非常不同的级别上运行。线程在进程内运行多行执行。分叉是一种创建进程的方法。

    【讨论】:

      猜你喜欢
      • 2016-09-25
      • 2023-03-19
      • 2011-09-28
      • 1970-01-01
      • 2021-05-31
      • 2010-11-30
      • 2015-03-28
      • 2010-12-13
      • 1970-01-01
      相关资源
      最近更新 更多