2017-07-18 69 views
2

我有以下代码。多种方法的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(); 
    } 
} 

我意料的是,当我叫完成()方法和我期待的输出如下所有线程都将完成。

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

+5

锁只是确保在多个线程不会在同一时间进入受保护的代码。我认为你必须更多地等待所有的任务完成。可能会返回任务并将其存储在数组中,然后调用['Task.WaitAll'](https://msdn.microsoft.com/en-us/library/dd270695(v = vs.110).aspx) –

+0

我认为你需要1)将'IncrementAge()'中的任务保存到一个成员变量中,2)等待它在'Complete()中完成 或者你可以从'IncrementAge()'返回'Task'并等待使用['Task.WaitAll'](https://msdn.microsoft.com/en-us/library/dd270695(v = vs.110).aspx) – GreatAndPowerfulOz

+3

锁定与执行顺序无关它只是防止多重访问。 –

回答

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."); 
    } 
} 
+0

谢谢..那工作。 –

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

完美..谢谢 –