Winforms我应该多线程还是使用事件计时器?

时间:2023-02-03 21:03:02

I currently have a thread that listens for data from the network and then runs rules on it. I then want to pass the data to the GUI. I am worried about having a deadlock in the GUI. I cant figure out were to put the mutexes on the GUI side. I am also using c# and dotnet 3.5.

我目前有一个线程,它从网络中侦听数据,然后在其上运行规则。然后我想将数据传递给GUI。我担心GUI中出现死锁。我无法弄清楚将互斥体放在GUI端。我也在使用c#和dotnet 3.5。

What I have come up with is 1) Using a timer to create an event and dump the thread. Worried about performance. 2) Use an intermediary event to copy the data to GUI. 3) Dig in and figure out thread safe way of using GUI.

我想出的是1)使用计时器创建事件并转储线程。担心表现。 2)使用中间事件将数据复制到GUI。 3)挖掘并找出使用GUI的线程安全方式。

What do you think is best way to proceed?

你认为最好的方法是什么?

Edit: Here is the solution I am using. I pass in the changed element and then protect the big object with a mutex. I use helper function to switch threads using InvokeRequired then BeginInvoke with a delegate. Pulled from reading the answers and then following links until reaching Threading in Windows Forms by Jon Skeet.

编辑:这是我正在使用的解决方案。我传入更改的元素,然后使用互斥锁保护大对象。我使用helper函数来使用InvokeRequired切换线程,然后使用委托来切换BeginInvoke。阅读答案然后跟随链接,直到Jon Skeet在Windows窗体中进行线程处理。

  delegate void UInt32ParameterDelegate(UInt32 n);

  public void UpdateLocation(UInt32 n)
  {
     if (InvokeRequired)
     {
        // We're not in the UI thread, so we need to call BeginInvoke
        BeginInvoke(new UInt32ParameterDelegate(UpdateLocation), new object[] { n });
        return;
     }
     // Must be on the UI thread if we've got this far

     this.engine.location.UpdateBusy.WaitOne();
     // do the work in here

     this.engine.location.UpdateBusy.ReleaseMutex();

  }

6 个解决方案

#1


Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.

Windows窗体中的同步非常简单。您可以在后台线程中调用Control.Invoke()。线程将停止,直到委托在UI线程上运行完毕。根本不需要同步。

If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.

如果停止线程是一个问题,请使用Control.BeginInvoke()。如果线程在继续运行时可能会改变它们,则必须使用锁保护传递给委托的对象。在生产者 - 消费者场景中很少出现这种情况,线程可以简单地创建新对象。

Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.

确保您不经常调用()。比每秒大约1000次更频繁地执行它,并且UI线程将停止泵送Windows消息,通过处理调用请求而陷入困境。因为它是人类的眼睛,你想要取悦,每秒调用超过25次只是浪费精力。池中间导致集合对象。

#2


I hope I understand your problem correctly.

我希望我能正确理解你的问题。

After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.

后台线程读取数据并执行任何操作后,应使用Invoke调用GUI线程上的方法。该方法将更新应在GUI中更新的任何内容。

#3


Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.

永远不要在GUI线程上读取网络。在网络中断期间运行应用程序并且GUI因此挂起,这只是时间问题。这会让您的用户感到沮丧。

In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.

在您的情况下,我认为最好的方法是让后台线程完成读取操作。然后获取结果数据并通过SynchronizationContext Post或Send方法将其移回GUI线程。

#4


you should just pass an event from your network thread to your UI thread.

您应该只将一个事件从您的网络线程传递到您的UI线程。

then cross threads using begininvoke so you don't get a cross thread exception.

然后使用begininvoke交叉线程,这样就不会出现跨线程异常。

Need help getting info across a UI thread and another thread in C#

需要帮助在UI线程和C#中的另一个线程获取信息

#5


You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.

您可以使用后台工作程序在后台线程中处理数据引导,完成后您可以结束后台工作程序,触发它的RunWorkerCompletedEventHandler。在RunWorkerCompletedEventHandler中,您可以使用结果更新GUI线程。

#6


Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?

是不是更容易抛出一个代表谁提出一个事件,告知表单刷新自己?

#1


Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.

Windows窗体中的同步非常简单。您可以在后台线程中调用Control.Invoke()。线程将停止,直到委托在UI线程上运行完毕。根本不需要同步。

If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.

如果停止线程是一个问题,请使用Control.BeginInvoke()。如果线程在继续运行时可能会改变它们,则必须使用锁保护传递给委托的对象。在生产者 - 消费者场景中很少出现这种情况,线程可以简单地创建新对象。

Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.

确保您不经常调用()。比每秒大约1000次更频繁地执行它,并且UI线程将停止泵送Windows消息,通过处理调用请求而陷入困境。因为它是人类的眼睛,你想要取悦,每秒调用超过25次只是浪费精力。池中间导致集合对象。

#2


I hope I understand your problem correctly.

我希望我能正确理解你的问题。

After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.

后台线程读取数据并执行任何操作后,应使用Invoke调用GUI线程上的方法。该方法将更新应在GUI中更新的任何内容。

#3


Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.

永远不要在GUI线程上读取网络。在网络中断期间运行应用程序并且GUI因此挂起,这只是时间问题。这会让您的用户感到沮丧。

In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.

在您的情况下,我认为最好的方法是让后台线程完成读取操作。然后获取结果数据并通过SynchronizationContext Post或Send方法将其移回GUI线程。

#4


you should just pass an event from your network thread to your UI thread.

您应该只将一个事件从您的网络线程传递到您的UI线程。

then cross threads using begininvoke so you don't get a cross thread exception.

然后使用begininvoke交叉线程,这样就不会出现跨线程异常。

Need help getting info across a UI thread and another thread in C#

需要帮助在UI线程和C#中的另一个线程获取信息

#5


You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.

您可以使用后台工作程序在后台线程中处理数据引导,完成后您可以结束后台工作程序,触发它的RunWorkerCompletedEventHandler。在RunWorkerCompletedEventHandler中,您可以使用结果更新GUI线程。

#6


Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?

是不是更容易抛出一个代表谁提出一个事件,告知表单刷新自己?