【问题标题】:Method called twice in same moment方法在同一时刻调用了两次
【发布时间】:2014-01-21 13:15:41
【问题描述】:

我正在开发一个 Windows 窗体应用程序,并与一个非常严重的错误作斗争。该应用程序应该在本地机器上运行并处理来自服务器应用程序的请求。客户端应用程序如下所示:

public Reader mr_obj;

public Form1()
{
    mr_obj = new MyReader.Reader(7137);
    mr_obj.UserEvent += new ReaderEvent(UserEvent);
}

private void UserEvent(UserEvent e, long threadID)
{
   Thread.Sleep(1000);
   SafeSomethingToDB();
}

Reader() 对象将客户端应用程序连接到服务器应用程序。因此,在此之后,服务器应用程序能够触发客户端应用程序中的 UserEvent() 方法。现在的问题是,如果 UserEvent() 方法在一秒钟内被触发两次,则处理 UserEvents 的客户端应用程序会崩溃。 (它实际上不会崩溃,直到你终止任务,try catch 不会返回错误)

到目前为止,我尝试将 Thread.Sleep() 和 SafeSomethingToDB() 委托给另一个线程。这不起作用,因为服务器应用程序不会等到踏板完成。所以服务器应用程序没有在数据库中找到数据,因为它没有等待 1 秒...... 当我对后台工作人员执行此操作时,也会出现同样的问题。

是否有可能以某种并行方式同时处理这两个来自同一个服务器应用程序的触发器?

非常感谢任何建议

编辑:我认为锁定该方法不会导致应用程序同时处理两个触发器。为了让这个可见,我试过这个:

private void UserEventHandler(UserEvent e, long threadID)
        {
            lock (_lockObject)
            {
                MessageBox.Show("Messagebox 1");
                MessageBox.Show("Messagebox 2");
            }
        }

当第一个请求触发 UserEvent() “MessageBox1”出现。如果按 OK,则会出现“MessageBox2”。但是,如果在“Messagebox2”仍处于打开状态时再次触发 UserEvent,则不会出现“MessageBox1”。而不是应用程序开始挂起。当两个触发器确实同时被处理时,是否应该再次出现由 UserEvent() 的第二个触发器触发的“MessageBox1”?所以这两个触发器没有并行执行还是我在这里弄错了?

【问题讨论】:

  • 也将SaveSomethingToDB() 移动到线程中。
  • 已编辑,抱歉没有解释清楚。这也是委托的。但是服务器应用程序不会等待线程完成,因此它会在数据库中的条目生成之前继续。
  • 如果UserEvent() 方法在一秒内被触发两次,或者SafeSomethingToDB() 在一秒内被调用两次(或者SafeSomethingToDB() 方法在第一次通话已退出)?
  • 是的,锁定会导致调用一个接一个地处理,而不是同时处理。这就是锁定的全部意义所在。
  • @Roy Dictus 我现在将每一步都记录到了我的事件日志中。它似乎在 sleep() 和 SafeSomethingToDB() 方法之间崩溃。因此,如果在 SafeSomethingToDB() 完成工作之前触发事件,它可能会崩溃。

标签: c# .net multithreading winforms thread-safety


【解决方案1】:

在不知道您为什么要执行 SleepSafeSomethingToDB 究竟做了什么以及导致您的问题的原因的情况下,尝试同步调用:

private readonly object _lockObject = new object();

private void UserEvent(UserEvent e, long threadID)
{
   lock(_lockObject)
   {
       Thread.Sleep(1000);
       SafeSomethingToDB();
   }
}

【讨论】:

  • 感谢您的回复。不幸的是,这不起作用。执行两次仍然会导致挂起。看看我上面的编辑:)
【解决方案2】:

我认为一个简单的lock 同步对你有用,试试这个

public Reader mr_obj;
private static readonly object sync = new object();
public Form1()
{
    mr_obj = new MyReader.Reader(7137);
    mr_obj.UserEvent += new ReaderEvent(UserEvent);
}

private void UserEvent(UserEvent e, long threadID)
{
   lock(sync)
   {
      SafeSomethingToDB();
   }
}

【讨论】:

  • 感谢您的回复。不幸的是,锁定doues不起作用。看看我上面的编辑:)
  • 锁定背后的想法是确保只有一个线程在临界区工作,在您的编辑中,这正是预期的。到目前为止,我们无能为力,您必须确定关键部分并确保使用信号量或监视器(即锁)在线程之间同步,并确保从该部分取出任何模态窗口.
【解决方案3】:

正如您在 cmets 中所写,如果在第一次调用完成之前第二次调用 SafeSomethingToDB(),那么它会崩溃。所以换句话说:SafeSomethingToDB() 是不可重入的。

您可以做的是使用 Mutex(代表互斥),它在您的代码中定义了一个“关键部分”,这意味着代码在任何时候都只能有一个线程执行它。

例如:

private static Mutex mutex = new Mutex();

public void SafeSomethingToDB()
{
    mutex.WaitOne(); // wait until it is safe to enter the critical section

    // Critical section begins here
    DoWorkAndStuff();

    mutex.ReleaseMutex(); // indicate the end of the critical section
}

有关System.Threading.Mutex 的更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.threading.mutex(v=vs.110).aspx

【讨论】:

    猜你喜欢
    • 2012-02-23
    • 1970-01-01
    • 2017-10-15
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2011-09-11
    相关资源
    最近更新 更多