如何在C#中锁定单个线程

时间:2012-03-29 22:57:25

标签: c# .net winforms

我想在单个线程上“锁定”资源。我已经尝试了我能想到的每一种锁定机制,但我无法做到这一点。

在下面的示例中,当Timer触发时,我不希望DoSomething中的代码在ShowDialog返回之前执行。我希望lock语句只允许一个Form2实例返回,但这实际上都是在一个线程上运行,所以它不会阻止线程重新进入该代码块。

以下是一些示例代码,这不是我面临的确切场景,但它说明了问题。在我的实际代码中,我从连接的设备接收事件,因此没有计时器。

要重现,请创建Windows窗体应用程序并添加Form1和Form2。将此代码复制到Form1:

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    private static object _lock = new object();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        lock (_lock)
        {
            Form2 form2 = new Form2();
            form2.ShowDialog();
        }
    }
}

3 个答案:

答案 0 :(得分:4)

如果你使用ThreadStaticAttribute,那么旗帜就可以了。

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    [ThreadStatic]
    bool inEvent = false;

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        // if you want to stay here and wait instead of exiting, you could do:
        // while (inEvent);
        if (!inEvent)
        {
            inEvent = true;
            Form2 form2 = new Form2();
            form2.ShowDialog();
            inEvent = false;
        }
    }
}

答案 1 :(得分:1)

您无法创建表单的一个实例,将其存储在类变量中,然后使用检查其Visible属性吗?

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.visible.aspx

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    Form2 form2 = new Form2();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        if(!form2.Visible)
        {
           form2.ShowDialog();
        }
    }
}

答案 2 :(得分:1)

肖恩,听起来好像其他人没有解决你的实际问题。看起来你在一个简单的解决方案中提出了一个更大的问题。无论如何,锁定不会最终在同一个线程上工作。它用于阻止其他线程。如果在同一个线程上遇到锁定,它只会增加引用计数或其他内容,并允许条目仅阻塞其他线程,直到引用计数变为零。

所以最初我认为Mutex,Semaphore,SpinWait,SpinUntil会有所帮助,但是当他们最终阻止满足您阻止输入的需要时,您的应用程序将被锁定并等待,因为您在UI线程上所以你甚至无法关闭Form2(或者你正在处理的任何东西)。

说实话,我不知道解决问题的正确方法。我认为会有一个模式或内置功能来做到这一点,但我不知道它。但是,如果你可以创建另一个可以解决问题的线程,如下面的代码所示。

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    private readonly static object _lock = new object();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { OnTimerTick(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void OnTimerTick()
    {
        new System.Threading.Thread (DoSomething).Start();
    }

    private void DoSomething()
    {
        Console.WriteLine("Before Lock");

        lock(_lock)
        {
            // Do stuff...

            Form2 form2 = new Form2();
            form2.ShowDialog();

        }

        Console.WriteLine("After Lock");
    }
}
祝你好运。如果这有助于不要忘记投票这个答案。

谢谢, 汤姆