Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#非UI跨线程调用_C#_Multithreading_Invoke - Fatal编程技术网

C#非UI跨线程调用

C#非UI跨线程调用,c#,multithreading,invoke,C#,Multithreading,Invoke,我正在尝试用C#进行跨线程调用 每当我从线程B调用的静态方法调用在线程A上下文中创建的对象的方法时,该方法总是在线程B中运行。我不希望这样,我希望它与我正在调用其方法的线程A对象在同一线程上运行 Invoke对于UI调用非常有效,我已经阅读了几十篇文章,因此回答了有关跨线程表单/WPF调用的不同方法。然而,无论我尝试什么(事件处理、委托等),如果线程B调用线程A的对象方法,那么它总是在线程B中运行 为了解决这个问题,我应该找图书馆的哪一部分?如果相关,线程B当前会“旋转”,从网络端口读取数据,偶

我正在尝试用C#进行跨线程调用

每当我从线程B调用的静态方法调用在线程A上下文中创建的对象的方法时,该方法总是在线程B中运行。我不希望这样,我希望它与我正在调用其方法的线程A对象在同一线程上运行

Invoke对于UI调用非常有效,我已经阅读了几十篇文章,因此回答了有关跨线程表单/WPF调用的不同方法。然而,无论我尝试什么(事件处理、委托等),如果线程B调用线程A的对象方法,那么它总是在线程B中运行

为了解决这个问题,我应该找图书馆的哪一部分?如果相关,线程B当前会“旋转”,从网络端口读取数据,偶尔会通过在线程a中创建并使用参数化ThreadStart传入的委托调用线程a的对象方法

我不想改变范例,只是从一个线程(线程B)向另一个线程(线程a)发送消息(调用方法的请求)

编辑:


我的问题是“我应该在图书馆的哪一部分去解决这个问题?”答案似乎是否定的。如果我想清楚地描述消费和轮询,我必须编写自己的代码来处理它。

你要做的是滚动一种队列,并让线程监视该队列的工作。当线程A看到新工作进入队列时,它可以将其出列并完成工作,然后返回等待更多工作

下面是一些伪代码:

    public class ThreadAQueue
    {
        private Queue<delegate> _queue;
        private bool _quitWorking;

        public void EnqueueSomeWork(delegate work)
        {
            lock(_queue) 
            {
                _queue.Enqueue(work);
            }
        }

        private void DoTheWork()
        {
            while(!quitWorking) 
            {
                delegate myWork;

                lock(_queue)
                {
                    if(_queue.Count > 1)
                        myWork = _queue.Dequeue();
                }

                myWork();
            }
        }
    }
公共类ThreadAQueue
{
专用队列;
私人厕所;
公共无效排队工作(委托工作)
{
锁定(_队列)
{
_排队。排队(工作);
}
}
私有void DoTheWork()
{
当(!退出工作)
{
委派我的工作;
锁定(_队列)
{
如果(_queue.Count>1)
myWork=_queue.Dequeue();
}
我的作品();
}
}
}
每当我调用线程上运行的对象的方法时

对象不会在线程上运行

为了使其工作,您必须创建某种类型的队列,您可以将委托推入其中,该队列将定期检查线程a的主循环。类似这样,假设Something.MainThreadLoop是线程A的入口点:

public class Something
{
    private Queue<Action> actionQueue = new Queue<Action>();

    private volatile bool threadRunning = true;

    public void RunOnThread(Action action)
    {
        if (action == null)
            throw new ArgumentNullException("action");

        lock (actionQueue)
            actionQueue.Enqueue(action);
    }

    public void Stop()
    {
        threadRunning = false;
    }

    private void RunPendingActions()
    {
        while (actionQueue.Count > 0) {
            Action action;

            lock (actionQueue)
                action = actionQueue.Dequeue();

            action();
        }
    }

    public void MainThreadLoop()
    {
        while (threadRunning) {
            // Do the stuff you were already doing on this thread.

            // Then, periodically...
            RunPendingActions();
        }
    }
}

代码在线程上运行。对象没有(通常-请参见线程本地)绑定到特定线程。通过执行WinFormControl.Invoke或WPFControl.Invoke,您将分别向消息泵或调度程序发送一条消息,以便在以后运行一些代码

消息泵是这样的:

Message message;
while(GetMessage(&message))
{
    ProcessMessage(message);
}
Microsoft专门构建了UI控件和项目,以允许跨线程发布消息。从线程a调用方法将始终在线程a上执行该方法,即使它最终执行某种异步工作并提前返回

编辑:

我认为你需要的是生产者-消费者模式

忘记从你的主线程获取消息,这听起来像是你想要做的。从线程C中消耗

线程A正在做“更重要的事情”。线程B正在旋转,侦听消息。线程C正在使用这些消息


不需要跨线程编组。

编辑:我认为您可能需要使用System.Threading.AutoResteEvent类。MSDN文档中有一个很好的例子,一个线程在另一个线程上等待,我认为这与您尝试执行的操作类似: 特别要注意对trigger.WaitOne()和trigger.Set()的调用

编辑2:在阅读OP的新评论后,添加了选项#3

“每当我调用在线程A上运行的对象的方法时…”-对象不会在线程上“运行”,也不会真正属于任何线程,无论是哪个线程创建了对象

鉴于您的问题是关于“非UI跨线程调用”,我假设您已经熟悉“UI跨线程调用”。我可以看出WinForms会给您一种印象,即线程拥有一个对象,您需要向线程“发送消息”以使其执行某些操作

WinForm控件对象是一种特殊情况,因为如果与它们交互的线程不是创建它们的线程,那么它们就不能正常工作,但这不是由线程和对象交互的方式造成的

不管怎样,我们继续回答你的问题

首先,一个澄清问题的问题:您提到了线程B在做什么,但是线程a在被线程B“调用”之前在做什么

以下是一些我认为与你想做的事情大致相同的想法:

  • 在需要之前不要创建线程。与其让线程B“向线程a发送消息”,不如让线程B创建线程a(或者如果愿意,可以称之为线程C),并让它在那个时候开始执行

  • 如果您需要线程A已经存在,并且您只希望线程A一次处理一个线程B的事件,那么您可以让线程A等待,直到它收到来自线程B的通知。请看一下(感兴趣的派生类是ManualResetEvent和AutoResetEvent)

    线程A将在某个时刻调用WaitHandle.WaitOne(),这将导致它暂停并等待,直到线程B对同一WaitHandle对象调用WaitHandle.Set()

  • 如果线程A正忙于做其他事情,那么您可能需要设置某种标志变量。与#2中的WaitHandle概念类似,但您只希望线程B设置一个标志(可能只是一个布尔变量),向线程A发出它需要执行某些操作的信号,而不是导致线程A暂停。线程A是线程b
    Message message;
    while(GetMessage(&message))
    {
        ProcessMessage(message);
    }