multithreading 线程安全是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2033879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 01:06:26  来源:igfitidea点击:

What does threadsafe mean?

multithreadingthread-safetydefinition

提问by Vivek Bernard

Recently I tried to Access a textbox from a thread (other than the UI thread) and an exception was thrown. It said something about the "code not being thread safe" and so I ended up writing a delegate (sample from MSDN helped) and calling it instead.

最近我试图从一个线程(而不是 UI 线程)访问一个文本框并且抛出了一个异常。它说了一些关于“代码不是线程安全的”,所以我最终编写了一个委托(来自 MSDN 的示例有帮助)并改为调用它。

But even so I didn't quite understand why all the extra code was necessary.

但即便如此,我还是不太明白为什么需要所有额外的代码。

Update: Will I run into any serious problems if I check

更新:如果我检查,我会遇到任何严重的问题吗

Controls.CheckForIllegalCrossThread..blah =true

采纳答案by Gregory Pakosz

Eric Lipperthas a nice blog post entitled What is this thing you call "thread safe"?about the definition of thread safety as found of Wikipedia.

Eric Lippert有一篇不错的博客文章,标题为“线程安全”是什么?关于维基百科中找到的线程安全的定义。

3 important things extracted from the links :

从链接中提取的 3 个重要内容:

“A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads.”

“In particular, it must satisfy the need for multiple threads to access the same shared data, …”

“…and the need for a shared piece of data to be accessed by only one thread at any given time.”

“如果一段代码在多个线程同时执行期间正确运行,那么它就是线程安全的。”

“特别是,它必须满足多个线程访问相同共享数据的需求,……”

“......并且需要在任何给定时间仅由一个线程访问共享数据。”

Definitely worth a read!

绝对值得一读!

回答by Vincent Ramdhanie

In the simplest of terms threadsafe means that it is safe to be accessed from multiple threads. When you are using multiple threads in a program and they are each attempting to access a common data structure or location in memory several bad things can happen. So, you add some extra code to prevent those bad things. For example, if two people were writing the same document at the same time, the second person to save will overwrite the work of the first person. To make it thread safe then, you have to force person 2 to wait for person 1 to complete their task before allowing person 2 to edit the document.

用最简单的术语来说,线程安全意味着从多个线程访问是安全的。当您在程序中使用多个线程并且它们每个都试图访问内存中的公共数据结构或位置时,可能会发生一些不好的事情。所以,你添加了一些额外的代码来防止那些不好的事情。例如,如果两个人同时编写同一个文档,则第二个人保存将覆盖第一个人的工作。为了确保线程安全,您必须强制第 2 个人等待第 1 个人完成他们的任务,然后再允许第 2 个人编辑文档。

回答by ChrisF

Wikipediahas an article on Thread Safety.

维基百科有一篇关于线程安全的文章。

This definitions page(you have to skip an ad - sorry) defines it thus:

这个定义页面(你必须跳过一个广告 - 抱歉)是这样定义的:

In computer programming, thread-safe describes a program portion or routine that can be called from multiple programming threads without unwanted interaction between the threads.

在计算机编程中,线程安全描述了可以从多个编程线程调用的程序部分或例程,而线程之间没有不需要的交互。

A thread is an execution path of a program. A single threaded program will only have one thread and so this problem doesn't arise. Virtually all GUI programs have multiple execution paths and hence threads - there are at least two, one for processing the display of the GUI and handing user input, and at least one other for actually performing the operations of the program.

线程是程序的执行路径。单线程程序只有一个线程,所以不会出现这个问题。几乎所有的 GUI 程序都有多个执行路径和线程——至少有两个,一个用于处理 GUI 的显示和处理用户输入,另一个用于实际执行程序的操作。

This is done so that the UI is still responsive while the program is working by offloading any long running process to any non-UI threads. These threads may be created once and exist for the lifetime of the program, or just get created when needed and destroyed when they've finished.

这样做是为了使 UI 在程序运行时仍然可以响应,将任何长时间运行的进程卸载到任何非 UI 线程。这些线程可以创建一次并在程序的生命周期内存在,或者在需要时创建并在它们完成时销毁。

As these threads will often need to perform common actions - disk i/o, outputting results to the screen etc. - these parts of the code will need to be written in such a way that they can handle being called from multiple threads, often at the same time. This will involve things like:

由于这些线程通常需要执行常见操作 - 磁盘 i/o、将结果输出到屏幕等 - 代码的这些部分需要以这样一种方式编写,即它们可以处理从多个线程调用,通常在同时。这将涉及以下内容:

  • Working on copies of data
  • Adding locks around the critical code
  • 处理数据副本
  • 在关键代码周围添加锁

回答by Sujith PS

Simply , thread safe means that a method or class instance can be used by multiple threads at the same time without any problems occurring.

简单地说,线程安全意味着一个方法或类实例可以被多个线程同时使用而不会出现任何问题。

Consider the following method:

考虑以下方法:

private int myInt = 0;
public int AddOne()
{
    int tmp = myInt;
    tmp = tmp + 1;
    myInt = tmp;
    return tmp;
}

Now thread A and thread B both would like to execute AddOne(). but A starts first and reads the value of myInt (0) into tmp. Now for some reason the scheduler decides to halt thread A and defer execution to thread B. Thread B now also reads the value of myInt (still 0) into it's own variable tmp. Thread B finishes the entire method, so in the end myInt = 1. And 1 is returned. Now it's Thread A's turn again. Thread A continues. And adds 1 to tmp (tmp was 0 for thread A). And then saves this value in myInt. myInt is again 1.

现在线程 A 和线程 B 都想执行 AddOne()。但是 A 首先启动并将 myInt (0) 的值读入 tmp。现在由于某种原因,调度程序决定停止线程 A 并将执行推迟到线程 B。线程 B 现在也将 myInt(仍为 0)的值读入它自己的变量 tmp。线程 B 完成了整个方法,所以最后 myInt = 1。返回 1。现在又轮到线程 A 了。线程 A 继续。并将 1 添加到 tmp (线程 A 的 tmp 为 0)。然后将此值保存在 myInt 中。myInt 又是 1。

So in this case the method AddOne was called two times, but because the method was not implemented in a thread safe way the value of myInt is not 2, as expected, but 1 because the second thread read the variable myInt before the first thread finished updating it.

所以在这种情况下,方法 AddOne 被调用了两次,但是因为该方法没有以线程安全的方式实现,所以 myInt 的值不是 2,正如预期的那样,而是 1,因为第二个线程在第一个线程完成之前读取了变量 myInt更新它。

Creating thread safe methods is very hard in non trivial cases. And there are quite a few techniques. In Java you can mark a method as synchronized, this means that only one thread can execute that method at a given time. The other threads wait in line. This makes a method thread safe, but if there is a lot of work to be done in a method, then this wastes a lot of space. Another technique is to 'mark only a small part of a method as synchronized'by creating a lock or semaphore, and locking this small part (usually called the critical section). There are even some methods that are implemented as lock-less thread safe, which means that they are built in such a way that multiple threads can race through them at the same time without ever causing problems, this can be the case when a method only executes one atomic call. Atomic calls are calls that can't be interrupted and can only be done by one thread at a time.

在非平凡的情况下,创建线程安全的方法是非常困难的。并且有相当多的技术。在 Java 中,您可以将方法标记为同步的,这意味着在给定时间只有一个线程可以执行该方法。其他线程排队等待。这使得方法线程安全,但是如果在一个方法中有很多工作要做,那么这会浪费很多空间。另一种技术是“仅将方法的一小部分标记为同步”通过创建锁或信号量,并锁定这一小部分(通常称为临界区)。甚至有一些方法被实现为无锁线程安全,这意味着它们的构建方式使得多个线程可以同时通过它们而不会引起问题,这可能是一种情况执行一个原子调用。原子调用是不能被中断的调用,一次只能由一个线程完成。

回答by Yasir Shabbir Choudhary

In real world example for the layman is

在现实世界中,外行的例子是

Let's suppose you have a bank account with the internet and mobile banking and your account have only $10. You performed transfer balance to another account using mobile banking, and the meantime, you did online shopping using the same bank account. If this bank account is not threadsafe, then the bank allows you to perform two transactions at the same time and then the bank will become bankrupt.

假设您有一个网上银行和手机银行的银行账户,而您的账户只有 10 美元。您使用手机银行将余额转入另一个账户,同时您使用同一个银行账户进行网上购物。如果这个银行账户不是线程安全的,那么银行允许你同时执行两个交易,然后银行就会破产。

Threadsafe means that an object's state doesn't change if simultaneously multiple threads try to access the object.

线程安全意味着如果多个线程同时尝试访问对象,则对象的状态不会改变。

回答by Hymany

You can get more explanation from the book "Java Concurrency in Practice":

你可以从《Java Concurrency in Practice》一书中得到更多解释:

A class is thread‐safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

如果一个类在从多个线程访问时行为正确,则该类是线程安全的,无论运行时环境对这些线程的执行进行调度或交错,并且调用代码部分没有额外的同步或其他协调。

回答by Chris Vest

A module is thread-safe if it guarantees it can maintain its invariants in the face of multi-threaded and concurrence use.

如果一个模块保证在面对多线程和并发使用时可以保持其不变量,那么它就是线程安全的。

Here, a module can be a data-structure, class, object, method/procedure or function. Basically scoped piece of code and related data.

在这里,模块可以是数据结构、类、对象、方法/过程或函数。基本上限定范围的一段代码和相关数据。

The guarantee can potentially be limited to certain environments such as a specific CPU architecture, but must hold for those environments. If there is no explicit delimitation of environments, then it is usually taken to imply that it holds for all environments that the code can be compiled and executed.

该保证可能仅限于某些环境,例如特定的 CPU 架构,但必须适用于这些环境。如果没有明确界定环境,则通常认为它适用于所有环境都可以编译和执行代码。

Thread-unsafe modules mayfunction correctly under mutli-threaded and concurrent use, but this is often more down to luck and coincidence, than careful design. Even if some module does not break for you under, it may break when moved to other environments.

线程不安全模块可能在多线程和并发使用下正常运行,但这通常更多地取决于运气和巧合,而不是精心设计。即使某些模块在您的情况下不会损坏,但当移动到其他环境时它可能会损坏。

Multi-threading bugs are often hard to debug. Some of them only happen occasionally, while others manifest aggressively - this too, can be environment specific. They can manifest as subtly wrong results, or deadlocks. They can mess up data-structures in unpredictable ways, and cause other seemingly impossible bugs to appear in other remote parts of the code. It can be very application specific, so it is hard to give a general description.

多线程错误通常很难调试。其中一些只是偶尔发生,而另一些则表现得咄咄逼人——这也可能是特定于环境的。它们可能表现为微妙的错误结果或僵局。它们可以以不可预测的方式弄乱数据结构,并导致其他看似不可能的错误出现在代码的其他远程部分。它可能非常特定于应用程序,因此很难给出一般性描述。

回答by Ravindra babu

Thread safety: A thread safe program protects it's data from memory consistency errors. In a highly multi-threaded program, a thread safe program does not cause any side effects with multiple read/write operations from multiple threads on same objects. Different threads can share and modify object data without consistency errors.

线程安全:线程安全程序保护其数据免受内存一致性错误的影响。在高度多线程的程序中,线程安全的程序不会对同一对象的多个线程的多个读/写操作产生任何副作用。不同的线程可以共享和修改对象数据而不会出现一致性错误。

You can achieve thread safety by using advanced concurrency API. This documentation pageprovides good programming constructs to achieve thread safety.

您可以通过使用高级并发 API 来实现线程安全。此文档页面提供了实现线程安全的良好编程结构。

Lock Objectssupport locking idioms that simplify many concurrent applications.

锁定对象支持简化许多并发应用程序的锁定习惯用法。

Executorsdefine a high-level API for launching and managing threads. Executor implementations provided by java.util.concurrent provide thread pool management suitable for large-scale applications.

Executors定义了一个用于启动和管理线程的高级 API。java.util.concurrent 提供的 Executor 实现提供了适合大型应用程序的线程池管理。

Concurrent Collectionsmake it easier to manage large collections of data, and can greatly reduce the need for synchronization.

并发集合可以更轻松地管理大型数据集合,并且可以大大减少同步需求。

Atomic Variableshave features that minimize synchronization and help avoid memory consistency errors.

原子变量具有最小化同步并有助于避免内存一致性错误的功能。

ThreadLocalRandom(in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads.

ThreadLocalRandom(在 JDK 7 中)提供了从多个线程高效生成伪随机数的功能。

Refer to java.util.concurrentand java.util.concurrent.atomicpackages too for other programming constructs.

其他编程结构也请参考java.util.concurrentjava.util.concurrent.atomic包。

回答by Aaron Robson

I find the concept of http://en.wikipedia.org/wiki/Reentrancy_%28computing%29to be what I usually think of as unsafe threading which is when a method has and relies on a side effect such as a global variable.

我发现http://en.wikipedia.org/wiki/Reentrancy_%28computing%29的概念是我通常认为的不安全线程,即当方法具有并依赖于诸如全局变量之类的副作用时。

For example I have seen code that formatted floating point numbers to string, if two of these are run in different threads the global value of decimalSeparator can be permanently changed to '.'

例如,我看到将浮点数格式化为字符串的代码,如果其中两个在不同线程中运行,则decimalSeparator 的全局值可以永久更改为“。”

//built in global set to locale specific value (here a comma)
decimalSeparator = ','

function FormatDot(value : real):
    //save the current decimal character
    temp = decimalSeparator

    //set the global value to be 
    decimalSeparator = '.'

    //format() uses decimalSeparator behind the scenes
    result = format(value)

    //Put the original value back
    decimalSeparator = temp

回答by David M

You are clearly working in a WinForms environment. WinForms controls exhibit thread affinity, which means that the thread in which they are created is the only thread that can be used to access and update them. That is why you will find examples on MSDN and elsewhere demonstrating how to marshall the call back onto the main thread.

您显然是在 WinForms 环境中工作。WinForms 控件表现出线程关联,这意味着创建它们的线程是唯一可用于访问和更新它们的线程。这就是为什么您会在 MSDN 和其他地方找到演示如何将调用编组回主线程的示例。

Normal WinForms practice is to have a single thread that is dedicated to all your UI work.

正常的 WinForms 实践是拥有一个专用于所有 UI 工作的线程。