public class ThreadingIssue
{
int accum;
public void Squaring(int x)
{
// Creates a random pause to check for thread
int pauseFor = rnd.Next(1, 10);
Thread.Sleep(pauseFor);
accum += x*x;
}
public void DoSquaring()
{
accum = 0;
for (int i = 1; i <= 100; i++)
{
threads.Add(new Thread(() => Squaring(i)));
threads[i - 1].Start();
}
}
基本上我想每次都得到338350作为答案,但显然我没有,因为存在线程问题。我试图创建一个像这样的对象:
private System.Object lockThis = new System.Object();
然后像这样锁定accum变量:
lock (lockThis)
{
accum += x*x;
}
但这并不能解决问题。我错过了什么/做错了什么?
答案 0 :(得分:7)
你的for
循环有问题。
for (int i = 1; i <= 100; i++)
{
threads.Add(new Thread(() => Squaring(i)));
threads[i - 1].Start();
}
在启动每个线程时,lambda i
内部使用循环变量() => Squaring(i)
,但是在创建任何线程时,循环已完成,i
的值为{{ 1}}。
要解决此问题,您需要在循环中捕获101
的副本并使用它。
试试这个:
i
您还需要在for (int i = 1; i <= 100; i++)
{
int j = i;
threads.Add(new Thread(() => Squaring(j)));
threads[i - 1].Start();
}
行附近lock
。
accum += x * x;
答案 1 :(得分:2)
我知道这并不是严格要求的,但为了引导你朝着正确的方向前进,这项任务完全适用于非常小的Linq和Tasks.Parallel:
var bag = new ConcurrentBag<KeyValuePair<int, int>>();
Parallel.For(1, 101,
i =>
{
bag.Add(new KeyValuePair<int, int>(i, i * i));
});
var squares = bag.ToDictionary(pair => pair.Key, pair => pair.Value);
Console.WriteLine("Square of 56 is " + squares[56].ToString());
Console.WriteLine("Sum of all squares is " + squares.Sum(pair => pair.Value).ToString());
这利用了相对较新的System.Collections.Concurrent
命名空间来完全消除了手动管理锁的需要,并利用System.Threading.Tasks
命名空间来并行化工作负载。循环使用许多线程填充集合,让操作系统决定它将产生多少个线程以保持系统响应,并且在它被强制转换为字典后,您可以随意执行任何操作。您还可以将ParallelOptions
实例传递给Parallel.For()
调用,以指定任务是短期还是长期运行,以告诉操作系统应如何对其进行优先级排序,并指定最大并行度。任务。
请确保您没有在表单的主要线程上使用Tasks.Parallel。
答案 2 :(得分:1)
首先,这样做:
public class ThreadingIssue
{
int accum;
private readonly object _syncLock = new object();
public void Squaring(int x)
{
// Creates a random pause to check for thread
int pauseFor = rnd.Next(1, 10);
Thread.Sleep(pauseFor);
lock( _syncLock )
{
accum += x*x;
}
}
public void DoSquaring()
{
accum = 0;
for (int i = 1; i <= 100; i++)
{
int number = i;
threads.Add(new Thread(() => Squaring(number)));
threads[i - 1].Start();
}
}
}