Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.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

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
.NET:如何让后台线程信号主线程数据可用?_.net_Multithreading_Asynchronous - Fatal编程技术网

.NET:如何让后台线程信号主线程数据可用?

.NET:如何让后台线程信号主线程数据可用?,.net,multithreading,asynchronous,.net,Multithreading,Asynchronous,让某个事件的ThreadA信号ThreadB,而不让ThreadB坐在等待事件发生的位置,正确的方法是什么 我有一个后台线程,将填写一个共享列表。我试图找到一种方法,以异步方式向“主”线程发出信号,表明有可用的数据可供提取 我考虑过使用EventWaitHandle对象设置事件,但我不能让我的主线程位于event.WaitOne() 我考虑过让代理回调,但是 a) 我不希望主线程在委托中工作:线程需要重新开始工作,添加更多的内容-我不希望它在委托执行时等待,并且 b) 委托需要封送到主线程,

让某个事件的ThreadA信号ThreadB,而不让ThreadB坐在等待事件发生的位置,正确的方法是什么

我有一个后台线程,将填写一个共享列表。我试图找到一种方法,以异步方式向“主”线程发出信号,表明有可用的数据可供提取


我考虑过使用EventWaitHandle对象设置事件,但我不能让我的主线程位于event.WaitOne()


我考虑过让代理回调,但是 a) 我不希望主线程在委托中工作:线程需要重新开始工作,添加更多的内容-我不希望它在委托执行时等待,并且 b) 委托需要封送到主线程,但我没有运行UI,我没有控制权。对调用委托


我考虑使用一个委托回调,它只启动一个零间隔System.Windows.Forms.Timer(同步对计时器的线程访问)。这样,线程只需要在调用时卡住

Timer.Enabled=true

但这似乎是一个黑客

在过去,我的对象会创建一个隐藏窗口,并让线程将消息发布到该隐藏窗口的HWND。我曾考虑创建一个隐藏控件,但我推测您不能。在未创建句柄的控件上调用。另外,我没有UI:我的对象可能是在web服务器、服务或控制台上创建的,我不希望出现图形控件,也不希望编译对System.Windows.Forms的依赖关系


我考虑让我的对象公开一个ISynchronizeInvoke接口,但是我需要实现.Invoke(),这就是我的问题



如果使用backgroundworker启动第二个线程并使用ProgressChanged事件通知另一个线程数据已准备就绪,那么让线程A向某个事件的线程B发送信号,而不让线程B被阻塞等待事件发生,正确的技术是什么。还有其他活动

有很多方法可以做到这一点,具体取决于您想要做什么。A可能是你想要的。要深入了解线程,请参阅优秀书籍中关于(在线提供)的章节。

您可以使用自动重置事件(或手动重置事件)。如果使用AutoResetEvent.WaitOne(0,false),它将不会阻塞。例如:

AutoResetEvent ev = new AutoResetEvent(false);
...
if(ev.WaitOne(0, false)) {
  // event happened
}
else {
 // do other stuff
}
如果您的“主”线程是Windows消息泵(GUI)线程,那么您可以使用Forms.Timer进行轮询-根据GUI线程“注意”工作线程中数据的速度调整计时器间隔

如果要使用
foreach
,请记住同步对共享
列表的访问,以避免
CollectionModified
异常


我将此技术用于实时交易应用程序中所有市场数据驱动的GUI更新,效果非常好。

我在这里结合了一些回应

理想的情况是使用线程安全标志,例如
AutoResetEvent
。调用
WaitOne()
时,不必无限期地阻塞,事实上它有一个重载,允许您指定超时。如果间隔期间未设置标志,此重载将返回
false

队列
对于生产者/消费者关系来说是一种更理想的结构,但是如果您的需求迫使您使用
列表
,您可以模仿它。主要区别在于,您必须确保您的消费者在提取物品时锁定对该收藏的访问;最安全的方法可能是使用
CopyTo
方法将所有元素复制到一个数组中,然后释放锁。当然,请确保您的制作人在锁定期间不会尝试更新
列表

下面是一个简单的C#控制台应用程序,它演示了如何实现这一点。如果你玩弄时间间隔,你可能会导致各种事情发生;在这个特定的配置中,我试图让生产者在消费者检查项目之前生成多个项目

using System;
using System.Collections.Generic;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        private static object LockObject = new Object();

        private static AutoResetEvent _flag;
        private static Queue<int> _list;

        static void Main(string[] args)
        {
            _list = new Queue<int>();
            _flag = new AutoResetEvent(false);

            ThreadPool.QueueUserWorkItem(ProducerThread);

            int itemCount = 0;

            while (itemCount < 10)
            {
                if (_flag.WaitOne(0))
                {
                    // there was an item
                    lock (LockObject)
                    {
                        Console.WriteLine("Items in queue:");
                        while (_list.Count > 0)
                        {
                            Console.WriteLine("Found item {0}.", _list.Dequeue());
                            itemCount++;
                        }
                    }
                }
                else
                {
                    Console.WriteLine("No items in queue.");
                    Thread.Sleep(125);
                }
            }
        }

        private static void ProducerThread(object state)
        {
            Random rng = new Random();

            Thread.Sleep(250);

            for (int i = 0; i < 10; i++)
            {
                lock (LockObject)
                {
                    _list.Enqueue(rng.Next(0, 100));
                    _flag.Set();
                    Thread.Sleep(rng.Next(0, 250));
                }
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统线程;
命名空间控制台应用程序1
{
班级计划
{
私有静态对象LockObject=新对象();
私有静态自动重置事件_标志;
私有静态队列列表;
静态void Main(字符串[]参数)
{
_列表=新队列();
_标志=新自动重置事件(假);
ThreadPool.QueueUserWorkItem(ProducerThread);
int itemCount=0;
而(itemCount<10)
{
如果(_flag.WaitOne(0))
{
//有一个项目
锁定(锁定对象)
{
Console.WriteLine(“队列中的项目:”);
而(_list.Count>0)
{
WriteLine(“找到的项{0}.”,_list.Dequeue());
itemCount++;
}
}
}
其他的
{
Console.WriteLine(“队列中没有项目”);
睡眠(125);
}
}
}
私有静态void ProducerThread(对象状态)
{
随机rng=新随机();
睡眠(250);
对于(int i=0;i<10;i++)
{
锁定(锁定对象)
{
_排队(rng.Next(0100));
_flag.Set();
线程睡眠(rng.Next(0250));
}
}
}
}
}
如果你不想阻止艾尔的制片人
    private static BackgroundWorker worker = new BackgroundWorker();
    static void Main(string[] args)
    {
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;

        Console.WriteLine("Starting application.");
        worker.RunWorkerAsync();

        Console.ReadKey();
    }

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Console.WriteLine("Progress.");
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        Console.WriteLine("Starting doing some work now.");

        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(1000);
            worker.ReportProgress(i);
        }
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("Done now.");
    }
this.asyncOperation = AsyncOperationManager.CreateOperation(null);
this.asyncOperation.Post(delegateMethod, arg);