C# 在多种方法中锁定对象



我有下面的代码。

public class AgeIncrementor
{
private static readonly object syncLock = new object();
public AgeIncrementor()
{
Age = 0;
}
public int Age { get; set; }
public void IncrementAge()
{
Task.Run(() =>
{
try
{
lock (syncLock)
{
Age += 10;
Console.WriteLine("Increased to {0}", Age);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
}
public void Complete()
{
Console.WriteLine("Printing from Complete() method.");
}
}

主方法代码如下:

class Program
{
static void Main(string[] args)
{
var ageIncrementor = new AgeIncrementor();
Console.WriteLine("Age is {0}", ageIncrementor.Age);
for (int i = 0; i < 5; i++)
{
ageIncrementor.IncrementAge();
}
ageIncrementor.Complete();
Console.WriteLine("Completed");
Console.WriteLine("Final Age is {0}", ageIncrementor.Age);
Console.ReadKey();
}
}

我的期望是,当我调用 Complete(( 方法时,所有线程都将完成,我期待输出如下。

Age is 0
Increased to 10
Increased to 20
Increased to 30
Increased to 40
Increased to 50
Printing from Complete() method.
Completed
Final Age is 50

但是我得到以下输出,如下所示。

Age is 0
Printing from Complete() method.
Completed
Final Age is 0
Increased to 10
Increased to 20
Increased to 30
Increased to 40
Increased to 50

如何确保运行 IncrementAge(( 方法的所有线程都应执行?

您正在启动多个线程,但不等待它们完成。lock只是一个互斥体,无法控制秩序。 如果更改IncrementAge以返回Task,然后等待任务,则代码将正确完成。 请注意,这仍然可能不按顺序运行。

class Program
{
static void Main(string[] args)
{
var ageIncrementor = new AgeIncrementor();
Console.WriteLine("Age is {0}", ageIncrementor.Age);
var tasks = Enumerable.Range(0, 5)
.Select(i => ageIncrementor.IncrementAge(i))
.ToArray();
Task.WaitAll(tasks);
ageIncrementor.Complete();
Console.WriteLine("Completed");
Console.WriteLine("Final Age is {0}", ageIncrementor.Age);
Console.ReadKey();
}
}
// watch the numbers passed in when the different tasks were started
public class AgeIncrementor
{
//doesn't need to be static since you are only using one instance
private readonly object syncLock = new object();
private Random Random = new Random();
public int Age { get; set; }
public Task IncrementAge(int index)
{
return Task.Run(() =>
{
// act like work before lock
Thread.Sleep(this.Random.Next(10) * 10);
lock (syncLock)
{
// act like work before change                      
Thread.Sleep(this.Random.Next(10) * 10);
Age += 10;                    
// act like work after change before release
Thread.Sleep(this.Random.Next(10) * 10);
Console.WriteLine("Increased to {0} ({1})", Age, index);
}
});
}
public void Complete()
{
Console.WriteLine("Printing from Complete() method.");
}
}

Lock 只是确保多个线程不会同时输入受保护的代码。 我认为您必须更多地考虑等待所有任务完成。 也许返回任务并将其存储在数组中,然后调用Task.WaitAll

IDEONE:

var ageIncrementor = new AgeIncrementor();
Console.WriteLine("Age is {0}", ageIncrementor.Age);
List<Task> tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(ageIncrementor.IncrementAge());
}
Task.WaitAll(tasks.ToArray());
ageIncrementor.Complete();
Console.WriteLine("Completed");
Console.WriteLine("Final Age is {0}", ageIncrementor.Age);
Console.ReadKey();

最新更新