gpt4 book ai didi

multithreading - 我们可以在单线程程序中使用竞争条件吗?

转载 作者:行者123 更新时间:2023-12-03 11:20:58 25 4
gpt4 key购买 nike

您可以在 here 上找到关于什么是竞态条件的一个很好的解释。

我最近看到很多人对竞争条件和线程做出令人困惑的陈述。

我了解到竞争条件只能发生在线程之间。但是我在基于事件和异步的语言中看到了看起来像竞争条件的代码,即使程序是单线程的,比如在 Node.js 中,在 GTK+ 中,等等。

我们可以在单线程程序中存在竞争条件吗?

最佳答案

所有示例都使用非常接近 Javascript 的虚构语言。

短的:

  • 竞争条件只能发生 之间 两个或多个线程/外部状态(其中之一可以是操作系统)。我们不能 在单线程进程中存在竞争条件,非 I/O 执行程序。
  • 但是在许多情况下,单线程程序可以:
  • 给出看起来类似于竞争条件的情况,例如在具有事件循环的基于事件的程序中,但是 不是真正的比赛条件
  • 例如,触发其他线程之间或与其他线程之间的竞争条件,或者因为程序某些部分的执行取决于外部状态:
  • 其他程序,如客户端
  • 库线程或服务器
  • 系统时钟

  • I) 竞争条件只能在两个或多个线程中发生

    只有当两个或多个线程试图访问共享资源而不知道它同时被 修改时,才会发生竞争条件。未知说明 来自其他线程。这给出了 未定结果 . (这真的很重要。)

    一个单线程进程无非是一个 的序列已知说明 因此导致 确定结果 ,即使指令的执行顺序在代码中也不容易读懂。

    II) 但我们并不安全

    II.1) 类似于竞态条件的情况

    许多编程语言通过事件或信号实现异步编程功能,由检查事件队列并触发监听器的主循环或事件循环处理。这方面的例子是 Javascript、libuevent、reactPHP、GNOME GLib……有时,我们可以找到似乎是竞争条件的情况, 但他们不是 .

    事件循环的调用方式总是 已知 ,所以结果是 确定 ,即使指令的执行顺序不容易阅读(甚至不知道库就无法阅读)。

    例子:
    setTimeout(
    function() { console.log("EVENT LOOP CALLED"); },
    1
    ); // We want to print EVENT LOOP CALLED after 1 milliseconds

    var now = new Date();
    while(new Date() - now < 10) //We do something during 10 milliseconds

    console.log("EVENT LOOP NOT CALLED");

    在 Javascript 输出中是 总是 (你可以在 node.js 中测试):
    EVENT LOOP NOT CALLED
    EVENT LOOP CALLED

    因为,当堆栈为空时(所有函数都已返回)调用事件循环。

    请注意,这只是一个示例,在以不同方式实现事件的语言中,结果可能不同,但仍由实现决定。

    II.2) 其他线程之间的竞争条件,例如:

    II.2.i) 使用客户端等其他程序

    如果其他进程正在请求我们的进程,我们的程序不会以原子方式处理请求,并且我们的进程在请求之间共享一些资源,则客户端之间可能存在竞争条件。

    例子:
    var step;
    on('requestOpen')(
    function() {
    step = 0;
    }
    );

    on('requestData')(
    function() {
    step = step + 1;
    }
    );

    on('requestEnd')(
    function() {
    step = step +1; //step should be 2 after that
    sendResponse(step);
    }
    );

    在这里,我们有一个经典的竞争条件设置。如果一个请求在另一个结束之前打开, step将被重置为 0。如果两个 requestData事件在 requestEnd 之前触发因为有两个并发请求,step 会达到 3。但这是因为我们将事件的顺序视为未确定。我们期望程序的结果大部分时间都是不确定的,输入是不确定的。

    事实上,如果我们的程序是单线程的, 给定一系列事件 结果始终是确定的。竞争条件是 客户之间 .

    有两种方法可以理解这件事:
  • 我们可以将客户端视为我们程序的一部分(为什么不呢?),在这种情况下,我们的程序是多线程的。故事的结局。
  • 更常见的是,我们可以认为客户不是我们计划的一部分。在这种情况下,它们只是 输入 .当我们考虑一个程序是否有确定的结果时,我们用 来做。给定输入 .否则即使是最简单的程序 return input;会有不确定的结果。

  • 注意 :
  • 如果我们的进程以原子方式处理请求,就像客户端之间存在互斥锁一样,并且没有竞争条件。
  • 如果我们可以识别请求并将变量附加到请求的每一步都相同的请求对象,则客户端之间没有共享资源,也没有竞争条件

  • II.2.ii) 使用库线程

    在我们的程序中,我们经常使用产生其他进程或线程的库,或者只是与其他进程进行 I/O(I/O 总是不确定的)。

    例子 :
    databaseClient.sendRequest('add Me to the database');

    databaseClient.sendRequest('remove Me from the database');

    这可能会触发异步库中的竞争条件。如果 sendRequest() 就是这种情况在将请求发送到数据库之后,但在请求真正执行之前返回。我们立即发送另一个请求,我们无法知道第一个请求是否会在第二个被评估之前执行,因为数据库在另一个线程上工作。存在竞争条件 程序和数据库进程之间 .

    但是,如果数据库与程序在同一个线程上(这在现实生活中并不经常发生),那么在处理请求之前 sendRequest 就不可能返回。 (除非请求被排队,但在这种情况下,结果仍然是 确定 因为我们确切地知道如何以及何时读取队列。)

    II.2.i) 带系统时钟

    @mingwei-samuel 的回答给出了一个单线程 JS 程序的竞争条件示例,介于 setTimeout 之间打回来。实际上,一旦两者 setTimeout被调用,执行顺序已经确定。此顺序取决于 setTimeout 时的系统时钟状态(因此,外部线程)称呼。

    结论

    简而言之,单线程程序不能免于触发竞争条件。但它们只能发生 与或在外部程序的其他线程之间 .我们程序的结果可能是不确定的,因为我们的程序从其他程序接收的输入是不确定的。

    关于multithreading - 我们可以在单线程程序中使用竞争条件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21463377/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com