我们可以在单线程程序中设置竞争条件吗? [英] Can we have race conditions in a single-thread program?

查看:24
本文介绍了我们可以在单线程程序中设置竞争条件吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以在此处上找到关于什么是竞态条件的非常好的解释.

You can find on here a very good explanation about what is a race condition.

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

I have seen recently many people making confusing statements about race conditions and threads.

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

I have learned that race conditions could only occur between threads. But I saw code that looked like race conditions, in event and asynchronous based languages, even if the program was single thread, like in Node.js, in GTK+, etc.

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

Can we have a race condition in a single thread program?

推荐答案

所有示例均采用非常接近 Javascript 的虚构语言.

简称:

  1. 竞争条件只能发生两个或多个线程/外部状态(其中之一可以是操作系统).我们不能在单线程进程、非 I/O 执行程序中存在竞争条件.

  1. A race condition can only occur between two or more threads / external state (one of them can be the OS). We cannot have race conditions inside a single thread process, non I/O doing program.

但是单线程程序在很多情况下可以:

But a single thread program can in many cases :

  1. 给出看起来类似于竞争条件的情况,比如在基于事件的程序中使用事件循环,但不是真正的竞争条件

在其他线程之间或与其他线程之间触发竞争条件,例如,或者因为程序的某些部分的执行取决于外部状态:

trigger a race condition between or with other thread(s), for example, or because the execution of some parts of the program depends on external state :

  1. 其他程序,例如客户端
  2. 库线程或服务器
  3. 系统时钟

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

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

I) Race conditions can only occur with two or more threads

A race condition can only occur when two or more threads try to access a shared resource without knowing it is modified at the same time by unknown instructions from the other thread(s). This gives an undetermined result. (This is really important.)

单线程进程只不过是一系列已知指令,因此导致确定的结果,即使指令的执行顺序不容易阅读在代码中.

A single thread process is nothing more than a sequence of known instructions which therefore results in a determined result, even if the execution order of instructions is not easy to read in the code.

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

Many programming languages implements asynchronous programming features through events or signals, handled by a main loop or event loop which check for the event queue and trigger the listeners. Example of this are Javascript, libuevent, reactPHP, GNOME GLib... Sometimes, we can find situations which seems to be race conditions, but they are not.

事件循环的调用方式总是已知,所以结果是确定的,即使指令的执行顺序不容易阅读(甚至不能如果我们不知道图书馆,请阅读).

The way the event loop is called is always known, so the result is determined, even if the execution order of instructions is not easy to read (or even cannot be read if we do not know the library).

示例:

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 中测试):

in Javascript output is always (you can test in node.js) :

EVENT LOOP NOT CALLED
EVENT LOOP CALLED

因为当栈为空时(所有函数都返回了),事件循环会被调用.

because, the event loop is called when the stack is empty (all functions have returned).

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

Be aware that this is just an example and that in languages that implements events in a different way, the result might be different, but it would still be determined by the implementation.

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

If other processes are requesting our process, that our program do not treat requests in an atomic way, and that our process share some resources between the requests, there might be a race condition between clients.

示例:

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 之前触发,因为两个并发请求,步长将达到 3.但这是因为我们将事件的顺序视为未确定.我们期望程序的结果大部分时间都是不确定的,输入未确定.

Here, we have a classical race condition setup. If a request is opened just before another ends, step will be reset to 0. If two requestData events are triggered before the requestEnd because of two concurrent requests, step will reach 3. But this is because we take the sequence of events as undetermined. We expect that the result of a program is most of the time undetermined with an undetermined input.

事实上,如果我们的程序是单线程的,给定一个事件序列,结果仍然总是确定的.竞争条件是客户端之间.

In fact, if our program is single thread, given a sequence of events the result is still always determined. The race condition is between clients.

理解这件事有两种方式:

There is two ways to understand the thing :

  • 我们可以将客户端视为我们程序的一部分(为什么不呢?),在这种情况下,我们的程序是多线程的.故事结束.
  • 更常见的情况是,我们认为客户不属于我们的计划.在这种情况下,它们只是输入.当我们考虑一个程序是否有确定的结果时,我们会使用给定的输入.否则即使是最简单的程序 return input; 也会有不确定的结果.
  • We can consider clients as part of our program (why not ?) and in this case, our program is multi thread. End of the story.
  • More commonly we can consider that clients are not part of our program. In this case they are just input. And when we consider if a program has a determined result or not, we do that with input given. Otherwise even the simplest program return input; would have a undetermined result.

注意:

  • 如果我们的进程以原子方式处理请求,就像客户端之间存在互斥一样,并且没有竞争条件.
  • 如果我们能够识别请求并将变量附加到请求的每一步都相同的请求对象,那么客户端之间就没有共享资源,也没有竞争条件
  • if our process treat request in an atomic way, it is the same as if there was a mutex between client, and there is no race condition.
  • if we can identify request and attach the variable to a request object which is the same at every step of the request, there is no shared resource between clients and no race condition

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

In our programs, we often use libraries which spawn other processes or threads, or that just do I/O with other processes (and I/O is always undetermined).

示例:

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

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

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

This can trigger a race condition in an asynchronous library. This is the case if sendRequest() returns after having sent the request to the database, but before the request is really executed. We immediately send another request and we cannot know if the first will be executed before the second is evaluated, because database works on another thread. There is a race condition between the program and the database process.

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

But, if the database was on the same thread as the program (which in real life does not happen often) is would be impossible that sendRequest returns before the request is processed. (Unless the request is queued, but in this case, the result is still determined as we know exactly how and when the queue is read.)

@mingwei-samuel 的回答给出了一个单线程 JS 程序竞争条件的例子,在 setTimeout 回调之间.实际上,一旦setTimeout都被调用,执行顺序就已经确定了.此顺序取决于 setTimeout 调用时的系统时钟状态(因此,外部线程).

@mingwei-samuel answer gives an example of a race condition with a single thread JS program, between to setTimeout callback. Actually, once both setTimeout are called, the execution order is already determined. This order depends on the system clock state (so, an external thread) at the time of setTimeout call.

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

In short, single-thread programs are not free from trigerring race conditions. But they can only occur with or between other threads of external programs. The result of our program might be undetermined, because the input our program receive from those other programs is undetermined.

这篇关于我们可以在单线程程序中设置竞争条件吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆