Viv*_*ard 114 multithreading definition thread-safety
最近我尝试从一个线程(UI线程除外)访问一个文本框,并抛出异常.它说了一些关于"代码不是线程安全的",所以我最终编写了一个代表(来自MSDN的示例帮助),然后调用它.
但即便如此,我也不太明白为什么所有额外的代码都是必要的.
更新:如果我检查,我会遇到任何严重的问题
Controls.CheckForIllegalCrossThread..blah =true
Run Code Online (Sandbox Code Playgroud)
Gre*_*osz 114
Eric Lippert有一篇很好的博客文章,名为"你称之为线程安全"的东西是什么?关于维基百科的线程安全定义.
从链接中提取的3件重要事项:
"如果一段代码在多线程同时执行期间正常运行,那么它就是线程安全的."
"特别是,它必须满足多线程访问相同共享数据的需要,......"
"......并且在任何给定时间只需要一个线程访问共享数据."
绝对值得一读!
Vin*_*nie 98
简单来说,线程安全意味着从多个线程访问是安全的.当您在程序中使用多个线程并且每个线程都试图访问内存中的公共数据结构或位置时,可能会发生一些不好的事情.所以,你添加一些额外的代码来防止这些坏事.例如,如果两个人同时写同一文档,则第二个保存的人将覆盖第一个人的工作.为了使线程安全,那么在允许人2编辑文档之前,必须强制人2等待人1完成他们的任务.
Chr*_*isF 16
维基百科有一篇关于线程安全的文章.
这个定义页面(你必须跳过广告 - 抱歉)这样定义它:
在计算机编程中,线程安全描述了可以从多个编程线程调用的程序部分或例程,而线程之间没有不希望的交互.
线程是程序的执行路径.单线程程序只有一个线程,因此不会出现此问题.实际上,所有GUI程序都具有多个执行路径,因此具有线程 - 至少有两个,一个用于处理GUI的显示并处理用户输入,另一个用于实际执行程序的操作.
这样做是为了在程序工作时UI仍然响应,将任何长时间运行的进程卸载到任何非UI线程.这些线程可以创建一次并在程序的生命周期中存在,或者只在需要时创建并在完成后销毁.
由于这些线程通常需要执行常见操作 - 磁盘i/o,将结果输出到屏幕等 - 代码的这些部分需要以这样的方式编写,即它们可以处理从多个线程调用,通常在同一时间.这将涉及以下内容:
Yas*_*ary 10
在现实世界中,外行的例子是
假设您有一个网上银行和手机银行的银行账户,而您的账户只有 10 美元。您使用手机银行将余额转入另一个账户,同时您使用同一个银行账户进行网上购物。如果这个银行账户不是线程安全的,那么银行允许你同时执行两个交易,然后银行就会破产。
线程安全意味着如果多个线程同时尝试访问对象,则对象的状态不会改变。
你可以从《Java Concurrency in Practice》一书中得到更多解释:
如果一个类在从多个线程访问时行为正确,则该类是线程安全的,无论运行时环境对这些线程的执行进行调度或交错,并且调用代码部分没有额外的同步或其他协调。
简单地说,线程安全意味着多个线程可以同时使用方法或类实例而不会出现任何问题.
请考虑以下方法:
private int myInt = 0;
public int AddOne()
{
int tmp = myInt;
tmp = tmp + 1;
myInt = tmp;
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
现在,线程A和线程B都想执行AddOne().但是A首先启动并将myInt(0)的值读入tmp.由于某种原因,调度程序决定暂停线程A并将执行推迟到线程B.线程B现在还将myInt(仍为0)的值读入其自己的变量tmp.线程B完成整个方法,所以最后myInt = 1.返回1.现在轮到A了.线程A继续.并且向tmp添加1(对于线程A,tmp为0).然后将此值保存在myInt中.myInt再次为1.
所以在这种情况下,AddOne方法被调用了两次,但由于该方法没有以线程安全的方式实现,myInt的值不是2,正如预期的那样,但是因为第二个线程在第一个线程完成之前读取变量myInt更新它.
在非平凡的情况下创建线程安全方法非常困难.而且有很多技巧.在Java中,您可以将方法标记为已同步,这意味着在给定时间只有一个线程可以执行该方法.其他线程排队等候.这使方法线程安全,但如果在方法中要做很多工作,那么这会浪费很多空间.另一种技术是"仅将方法的一小部分标记为同步"通过创建一个锁或信号量,并锁定这个小部分(通常称为临界区).甚至有一些方法被实现为无锁线程安全,这意味着它们以这样的方式构建,即多个线程可以同时通过它们而不会引起问题,这可能是仅在方法时的情况执行一个原子调用.原子调用是无法中断的调用,一次只能由一个线程完成.
如果一个模块保证在面对多线程和并发使用时可以保持其不变量,那么它就是线程安全的。
在这里,模块可以是数据结构、类、对象、方法/过程或函数。基本上限定范围的一段代码和相关数据。
该保证可能仅限于某些环境,例如特定的 CPU 架构,但必须适用于这些环境。如果没有明确界定环境,则通常认为它适用于所有环境都可以编译和执行代码。
线程不安全模块可能在多线程和并发使用下正常运行,但这通常更多地取决于运气和巧合,而不是精心设计。即使某些模块在您的情况下不会损坏,但当移动到其他环境时它可能会损坏。
多线程错误通常很难调试。其中一些只是偶尔发生,而另一些则表现得咄咄逼人——这也可能是特定于环境的。它们可能表现为微妙的错误结果或僵局。它们可以以不可预测的方式弄乱数据结构,并导致其他看似不可能的错误出现在代码的其他远程部分。它可能非常特定于应用程序,因此很难给出一般性描述。
归档时间: |
|
查看次数: |
70490 次 |
最近记录: |