通用BeginInvoke方案,以确保在相同的线程上下文中调用函数 [英] Generic BeginInvoke Scheme to ensure function calls in same threading context
问题描述
我将一些代码从winforms控制对象移到一个单独的对象,以实现更好的模块化.但是,有一些对发出回调的外部对象的调用,我无法控制这些回调,并且可以从不同线程中将其作为主UI线程触发.为了避免这种情况,我使用众所周知的BeginInvoke方案来检查是否应将调用转移到主UI线程.
I'm moving some code from a winforms control object to a separate object for better modularity. However, there some calls to an external object issuing callbacks, which I have no control of and which can be fired from different threads as the main UI thread. To avoid this I use the well known BeginInvoke scheme to check, whether a call should be transfered to the main UI thread.
现在,当我将此代码移到我的分离对象时,就不再需要Winforms引用了.我可以处理Control对象,以确保所有内容都在同一线程中运行.但是我想拥有一个通用机制,其功能与确保Threadconext完全相同,例如创建对象或调用特定的入口函数也用于后续发出的调用,例如通过外部回调.
When I now move this code to my separated object, I have not necessary a Winforms reference anymore. I could handle over a Control object to still ensure that everything is running in the same thread. But I would rather like to have a generic mechanism which does exactly the same like ensuring, that the Threadconext in which the e.g. the object was created or a specific entry function was called is also used for subsequent calls issued e.g. by external callbacks.
这最容易实现吗?
示例:
public class Example
{
ThreadedComponent _Cmp = new ThreadedComponent();
public Example()
{
_Cmp.ThreadedCallback += new ThreadedComponent.CB(Callback);
}
public void StartFunction()
{
// called in ThreadContextA
_Cmp.Start();
}
void Callback(Status s)
{
// is called in ThreadContextB
if(s == SomeStatus)
_Cmp.ContinueFunction(); // must be called in ThreadContextA
}
}
为澄清起见
ContinueFunction
.这不一定是UI线程,但目前它当然是按钮处理程序.
ContinueFunction
must be called from the same ThreadContext like StartFunction
was called. This is not necessarily a UI thread, but at the moment it is of course a button handler.
推荐答案
我使用运行自己的线程的单独队列解决了该问题.通过代理接口将函数调用添加到队列中.这可能不是最优雅的方法,但可以确保添加到队列中的所有内容都在队列的线程上下文中执行.这是一个非常原始的实现示例,仅用于展示基本思想:
I solve the problem using a separate queue which runs its own thread. Function Calls are added to the Queue with a Proxyinterface. It's probably not the most elegant way, but it ensures, that everything added to the queue is executed in the queue's threadcontext. This is a very primitive implementation example just to show the basic idea:
public class Example
{
ThreadQueue _QA = new ThreadQueue();
ThreadedComponent _Cmp = new ThreadedComponent();
public Example()
{
_Cmp.ThreadedCallback += new ThreadedComponent.CB(Callback);
_QA.Start();
}
public void StartFunction()
{
_QA.Enqueue(AT.Start, _Cmp);
}
void Callback(Status s)
{
// is called in ThreadContextB
if(s == SomeStatus)
_QA.Enqueue(new ThreadCompAction(AT.Continue, _Cmp);
}
}
public class ThreadQueue
{
public Queue<IThreadAction> _qActions = new Queue<IThreadAction>();
public Enqueue(IThreadAction a)
{
lock(_qActions)
_qActions.Enqueue(a);
}
public void Start()
{
_thWatchLoop = new Thread(new ThreadStart(ThreadWatchLoop));
_thWatchLoop.Start();
}
void ThreadWatchLoop()
{
// ThreadContext C
while(!bExitLoop)
{
lock (_qActions)
{
while(_qActions.Count > 0)
{
IThreadAction a = _qActions.Dequeue();
a.Execute();
}
}
}
}
}
public class ThreadCmpAction : IThreadAction
{
ThreadedComponent _Inst;
ActionType _AT;
ThreadCmpAction(ActionType AT, ThreadedComponent _Inst)
{
_Inst = Inst;
_AT = AT;
}
void Do()
{
switch(AT)
{
case AT.Start:
_Inst.Start();
case AT.Continue:
_Inst.ContinueFunction;
}
}
}
这篇关于通用BeginInvoke方案,以确保在相同的线程上下文中调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!