我曾在here询问有关锁的问题,人们回答我的锁实现没有问题。但我抓住了问题。这是相同的锁实现,我得到了奇怪的结果。我希望看到数字从1开始,但它从5开始。例如,在下面。
class Program
{
static object locker = new object();
static void Main(string[] args)
{
for (int j = 0; j < 100; j++)
{
(new Thread(new ParameterizedThreadStart(dostuff))).Start(j);
}
Console.ReadKey();
}
static void dostuff(dynamic input)
{
lock (locker)
{
Console.WriteLine(input);
}
}
}
答案 0 :(得分:3)
代码很好。但是你不能保证执行线程的顺序。当我运行代码时,我得到:
0 1 3 五 2 4 6 10 9 11 7 12 8 等
如果您需要按指定的顺序运行线程,可以考虑使用ThreadPool.QueueUserWorkItem
代替。
class Program
{
static object locker = new object();
static EventWaitHandle clearCount
=new EventWaitHandle(false, EventResetMode.ManualReset);
static void Main(string[] args)
{
for (int j = 0; j < 100; j++)
{
ThreadPool.QueueUserWorkItem(dostuff, j);
}
clearCount.WaitOne();
}
static void dostuff(dynamic input)
{
lock (locker)
{
Console.WriteLine(input);
if (input == 99) clearCount.Set();
}
}
}
答案 1 :(得分:1)
将锁放在您放置的位置是没有意义的,因为您没有锁定更改多个线程共享的值的代码。您锁定的代码部分根本不会更改任何变量。
数字出现故障的原因是因为线程无法保证以任何特定顺序启动,除非您执行@Mikael Svenson建议的操作。
有关共享变量的示例,如果您使用此代码:
class Program
{
static object locker = new object();
static int count=0;
static void Main(string[] args)
{
for (int j = 0; j < 100; j++)
{
(new Thread(new ParameterizedThreadStart(dostuff))).Start(j);
}
Console.ReadKey();
}
static void dostuff(object Id)
{
lock (locker)
{
count++;
Console.WriteLine("Thread {0}: Count is {1}", Id, count);
}
}
}
您可能会看到线程编号不按顺序排列,但计数是。如果删除lock语句,则计数也不会按顺序排列。
答案 2 :(得分:1)
这里有一些问题和错误的假设。
使用的最佳方法是将问题划分为单独的独立块,这些块可以使用尽可能少的线程同步来同时计算。这些分区应该在很小且相当静态的线程上执行。您可以使用ThreadPool
,Parallel
或Task
类来执行此操作。
我使用Parallel.For
方法包含了一个示例模式。为了使示例易于理解,假设您有一个要克隆的对象列表并将其放入单独的列表中。让我们假设克隆操作很昂贵,并且您希望并行化克隆许多对象。这是你怎么做的。请注意lock
关键字的展示位置和使用限制。
public static void Main()
{
List<ICloneable> original = GetCloneableObjects();
List<ICloneable> copies = new List<ICloneable>();
Parallel.For(0, 100,
i =>
{
ICloneable cloneable = original[i];
ICloneable copy = cloneable.Clone();
lock (copies)
{
copies.Add(copy);
}
});
}