Sis*_*hus 8 c# multithreading thread-safety
我最近在阅读Rob Miles(这里)的非常好的pdf时进入了Threads .他在第160页(2012年,C#pdf)上有一个例子,但它没有写入控制台只是空循环.
我写了一个非常简单的线程生成循环,它创建了10个线程,在1000的每个倍数上将它们的ID写入屏幕.这很好 - 它向我展示了线程如何一起运行.我的问题从为什么我的输出如此困惑开始?通常当我运行下面的程序时,我会得到多个"Thread 3 Finished"行,我很确定,我应该只有一个.
我从MSDN 添加了一个"锁定"到循环但它似乎仍然产生奇数输出(我将在下面举一个例子).
namespace ConsoleApplication1
{
class Program
{
static object sync = new object();
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread myThread = new Thread(() => DoThis(i));
myThread.Start();
}
Console.ReadLine();
}
static void DoThis(int s)
{
lock (sync) // a new addition that hasn't helped
{
for (long j = 0; j < 10000; j++)
{
if (j % 1000 == 0) Console.Write(String.Format("{0}.", s));
}
Console.WriteLine("\r\nThread {0} Finished", s);
Debug.Print("\r\nThread {0} Finished", s); //<-- added to debug
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我以为我做得很好 - 我有局部变量(我的计数循环),我有一个int传递大概不是通过引用,后来我试图锁定它做它的循环.没有快乐.我需要做些什么来使输出看起来合理?我试过Deubg.Print进行故障排除,但它也有错误(下面).
最终,我想在更大的应用程序中使用线程,但如果我不能在这里得到它,我不确定我想要!
示例最后从debug.print行输出:(注意倍数)...
Run Code Online (Sandbox Code Playgroud)Thread 1 Done The thread '<No Name>' (0x15cc) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x1d0c) has exited with code 0 (0x0). Thread 6 Done The thread '<No Name>' (0x2248) has exited with code 0 (0x0). Thread 10 Done The thread '<No Name>' (0x22bc) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x85c) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x1628) has exited with code 0 (0x0). Thread 3 Done The thread '<No Name>' (0x2384) has exited with code 0 (0x0). Thread 6 Done Thread 2 Done Thread 4 Done The thread '<No Name>' (0x2348) has exited with code 0 (0x0). The thread '<No Name>' (0x2420) has exited with code 0 (0x0). The thread '<No Name>' (0x1ea8) has exited with code 0 (0x0).
如果我能提供有关我尝试过的更多信息,请告诉我.
Mat*_*son 10
这里的问题是你在循环变量上使用了"修改后的闭包".
虽然这已针对foreach循环进行了修复,但for循环仍然存在问题(并且始终存在)
要解决此问题,请将Main()更改为:
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
int copy = i; // Make a copy of i to prevent the "modified closure" problem.
Thread myThread = new Thread(() => DoThis(copy));
myThread.Start();
}
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参见此处
尝试使用Parallel.For而不是在循环中自己启动线程:
Parallel.For(0, 10, DoThis);
Run Code Online (Sandbox Code Playgroud)
如果您需要传递一个额外的参数(比方说w)作为其中的一部分,那么您可以这样做:
var w = 4;
Parallel.For(0, 10, i => DoThis(i, w));
Run Code Online (Sandbox Code Playgroud)
当然要考虑的另一件事是该Console对象是独占的.如果您从一个线程使用它,那么尝试使用它的任何其他线程将被阻塞,直到它完成.
此外,您lock (sync)将阻止任何两个线程同时执行其操作.
请记住,不保证您的线程以任何特定顺序执行.