2014-03-02 94 views
0

我想知道这种方法是否有潜在的僵局。在Timer Tick事件中使用“锁定”是否死锁安全?

示例代码:当您单击应用程序按钮时,将创建一个Job对象并将其添加到作业列表中。添加代码受'锁定'保护。然后在计时器滴答事件中,我想从列表中删除已完成的作业 - 锁定计时器事件中的列表。

所以问题是,如果用户按下“添加作业”按钮,而计时器事件锁定正在使用,这个应用程序会死锁吗?

计时器是一个Windows窗体计时器。

public partial class Form1 : Form 
{ 
    object listLock = new object(); 
    List<Job> jobsList = new List<Job>(); 
    public Form1() 
    { 
     InitializeComponent(); 
     timer1.Start(); 
    } 

    private void timer1_Tick(object sender, EventArgs e) 
    { 
     Job aJob; 
     lock(listLock) 
     { 
      for (int i = jobsList.Count - 1; i > -1; i--) 
      { 
       aJob = jobsList[i]; 
       if (aJob.IsCompleted) 
       { 
        jobsList.RemoveAt(i); 
       } 

      } 
     } 

    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     lock (listLock) 
     { 
      Job aJob = new Job(); 
      jobsList.Add(aJob); 
     } 

    } 
} 

//===================================== 
    class Job 
    { 
     bool isCompleted = false; 

     public bool IsCompleted 
     { 
      get { return isCompleted; } 
      set { isCompleted = value; } 
     } 

     public Job() 
     { 
      // do some work then mark complete 
      IsCompleted = true; 
     } 
} 

回答

2

计时器事件(来自Windows窗体计时器)从主消息循环中调度。所以他们将永远不会与任何其他UI事件的处理程序重叠。

按下按钮将进入消息队列,并在定时器Tick处理程序完成后进行处理。 (因此,对于只由UI事件处理程序操作的数据结构,您不需要锁定,因为它们将按照它们排队的顺序依次运行)

+0

好的,谢谢你。那么如果另一个Windows窗体在这个窗体上调用一个公共方法来添加一个项目到这个列表呢?这仍然是死锁安全吗? –

+1

@LTDan:只要它们是从单个消息循环('Main'方法中的'Application.Run')控制的,那么它们共享一个队列并按顺序运行,没有竞争条件。只有从另一个线程访问数据结构时,才会出现数据冲突。 –