我有以下代码。
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()方法的所有线程都已执行?
答案 0 :(得分:3)
您正在启动多个线程但不等待它们完成。 lock
只是Mutex而且无法控制订单。如果您更改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.");
}
}
答案 1 :(得分:3)
锁定只是确保多个线程不会同时输入受保护的代码。我认为你必须更多地等待所有任务完成。也许返回任务并将其存储在一个数组中,然后调用Task.WaitAll
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();