C# c lock()在第二次尝试锁定时挂起

C# c lock()在第二次尝试锁定时挂起,c#,multithreading,locking,C#,Multithreading,Locking,编辑2-> 看看底部; 在现实世界中,我使用锁在serialPort上使用同步读/写(而不是异步读/写)来保护读/写/配置。我在dbg中看到了一些内部WaitOne调用。不知道是否相关。 当您呼叫时,它将执行以下操作: 在拥有控件底层窗口句柄的线程上执行指定的委托 它这样做的方式是将消息发布到所属线程的消息队列中,并等待该线程处理该消息 因此,Invoke是一个阻塞调用,在调用被调用的委托之前不会返回 现在,代码阻塞的可能原因是您的主GUI线程已经在等待其他事情发生,可能是您的外部程序已经完成

编辑2-> 看看底部; 在现实世界中,我使用锁在serialPort上使用同步读/写(而不是异步读/写)来保护读/写/配置。我在dbg中看到了一些内部WaitOne调用。不知道是否相关。 当您呼叫时,它将执行以下操作:

在拥有控件底层窗口句柄的线程上执行指定的委托

它这样做的方式是将消息发布到所属线程的消息队列中,并等待该线程处理该消息

因此,Invoke是一个阻塞调用,在调用被调用的委托之前不会返回

现在,代码阻塞的可能原因是您的主GUI线程已经在等待其他事情发生,可能是您的外部程序已经完成

因此,它实际上并不是在处理消息

如果这是原因,那么这里的解决方案是删除GUI线程的阻塞部分。不要坐在那里等待外部程序完成,而是旋转出一个等待它完成的任务,然后在它完成时在主窗体上引发适当的事件。同时,主线程可以自由处理消息、更新文本框等

请注意,这意味着如果启动外部程序是为了响应某个事件,如单击按钮,则可能需要在程序运行时禁用部分用户界面,以避免用户单击按钮两次,启动两次并行执行,这两次执行都将报告给同一文本框


结论:多线程编程很难

根据您的编辑,其中一个锁块内的串行I/O代码似乎已暂停。如果看不到实际的代码,很难猜测它为什么会被暂停……这段代码对我来说运行得非常完美。@SimonWhitehead-那么它是特定于平台/配置的吗?我用4.0CP的目标框架运行它,但“真正的”是3.5。。。这是我的机器,不是。。对我来说,平台更改似乎没有什么不同。它因调用而挂起,调用会将消息发布到表单的输入队列,然后等待处理该消息。如果拥有表单的线程被阻止,它将不会处理消息。
using System;

namespace LockTester
{
    public class Class1
    {
        object m_lock = null;
        bool m_isRunning;
        System.Threading.Thread m_thread = null;
        public Class1()
        {
            Console.WriteLine("Class1 ctor");
            m_lock = new object();
            m_isRunning = false;
        }
    
        public void DoSomething(){
            Console.WriteLine("DoSomething() Trying to acquire lock");
            lock(m_lock){
                Console.WriteLine("DoSomething() Acquired lock");
            }
            Console.WriteLine("DoSomething() Released lock");
        }
    
        public void Start(){
            Console.WriteLine("start()");
            m_isRunning = true;
            if (m_thread == null){
                m_thread = new System.Threading.Thread(Run);
            }
            m_thread.Start();
        }
    
        public void Stop(){
            Console.WriteLine("stop()");
            m_isRunning = false;
        }
    
        private void Run(){
            while (m_isRunning){
                Console.WriteLine("Trying to acquire lock");
                lock(m_lock){
                    Console.WriteLine("Acquired lock");
                    System.Threading.Thread.Sleep(1000);
                }
                Console.WriteLine("Released lock");
                System.Threading.Thread.Sleep(1000);
            }
        }
    }
}
public class TextBoxStreamWriter : TextWriter
{
    TextBox _output = null;
    Form _form = null;
    object _lock = new object();
    
    delegate void SetTextCallback(string text);
    
    private void SetText(string text)
    {
      // InvokeRequired required compares the thread ID of the
      // calling thread to the thread ID of the creating thread.
      // If these threads are different, it returns true.
      if (_output.InvokeRequired)
      { 
        SetTextCallback d = new SetTextCallback(SetText);
        _form.Invoke(d, new object[] { text });
      }
      else
      {
          _output.AppendText(text);
      }
    }
    
    
    public TextBoxStreamWriter(TextBox output, Form form)
    {
        _output = output;
        _form = form;
    }

    public override void Write(char value)
    {
        lock (_lock)
        {
            base.Write(value);
            SetText(value.ToString());
        }
    }

    public override Encoding Encoding
    {
        get { return System.Text.Encoding.UTF8; }
    }
}