C#以多种方法锁定对象

时间:2017-07-18 16:03:42

标签: c# multithreading c#-4.0 task-parallel-library

我有以下代码。

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()方法的所有线程都已执行?

2 个答案:

答案 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

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();