什么是适当的技术有 ThreadA 信号 的一些事件,没有 当被阻止在等待一个事件发生?

我有一个背景线,将会填补一个共用名单<T>.我试图找到一种方式是异步的信号的"主要的"螺纹,有数据可用。


我认为设置一个事件与安全访问对象,但是我不能拥有我的主线坐在一个事件。使用此().


我认为是具有代表回叫,但是 a)我不想要主线做的工作委托:螺纹需要回去工作增加更多的东西-我不想让它等待,同时委托执行, b)代表需要汇集到主线,但我不是运行一个用户界面,我没有控制。援引该代表反对。


我认为有一个代表回调,这只是开始一个零间系统。窗户。形式。计时器(用线访问的计时器同步)。这种方式的线只需要坚持,因为它要求

Timer.Enabled = true;

但是,这似乎是一个黑客。

在过去的日子里我对象就已经创建了一个隐秘的窗口和有线发布消息,隐藏窗口'HWND。我认为创造一个隐藏的控制,但是我收集,你不能。调用的控制没有处理创建的。另外,我有没有用户界面:我的对象可能已经创建了一个网络服务器、服务或控制台我不希望这是一个图形控制中出现的-我也不想编制的依赖性的系统。窗户。形式。


我认为有我的目的暴露ISynchronizeInvoke接口,但是然后我需要实施。援引(),这就是我的问题。


什么是适当的技术,以有线信号线B的一些事件,没有有线B的当阻止等待事件的发生?

有帮助吗?

解决方案

这是System.ComponentModel.BackgroundWorker类的代码示例。

    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.");
    }

其他提示

我在这里结合了一些回复。

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

对于生产者/消费者关系来说,Queue是一种更理想的结构,但如果您的要求强迫您使用List,则可以模仿它。主要区别在于您必须确保您的消费者在提取项目时锁定对集合的访问权限;最安全的事情是可能使用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));
                }
            }
        }
    }
}

如果你根本不想阻止制片人,那就更棘手了。在这种情况下,我建议使用私有和公共缓冲区以及公共<=>使生成器成为自己的类。生产者默认将项目存储在私有缓冲区中,然后尝试将它们写入公共缓冲区。当使用者使用公共缓冲区时,它会重置生成器对象上的标志。在生产者尝试将项目从私有缓冲区移动到公共缓冲区之前,它会检查此标志,并仅在消费者未处理项目时复制项目。

如果使用后台工作程序启动第二个线程并使用ProgressChanged事件通知另一个线程数据已准备就绪。其他活动也是如此。 这篇MSDN文章应该可以帮助您入门

有很多方法可以做到这一点,具体取决于你想要做什么。 生产者/消费者队列可能就是您想要的。要深入了解线程,请参阅线程(在线提供)一章。优秀的书籍 C#3.0 in a Nutshell

您可以使用AutoResetEvent(或ManualResetEvent)。如果您使用AutoResetEvent.WaitOne(0,false),它将不会阻止。例如:

AutoResetEvent ev = new AutoResetEvent(false);
...
if(ev.WaitOne(0, false)) {
  // event happened
}
else {
 // do other stuff
}

该BackgroundWorker类是答案在这种情况。它是唯一的线建造,是能够异步发送消息的 螺纹 创建该BackgroundWorker对象。内部 BackgroundWorker 使用 AsyncOperation 类的调用 asyncOperation.Post() 法。

this.asyncOperation = AsyncOperationManager.CreateOperation(null);
this.asyncOperation.Post(delegateMethod, arg);

一些其他类中。净框架还使用AsyncOperation:

  • BackgroundWorker
  • SoundPlayer.LoadAsync()
  • SmtpClient.SendAsync()
  • 平。SendAsync()
  • Web客户端.DownloadDataAsync()
  • Web客户端.DownloadFile()
  • Web客户端.DownloadFileAsync()
  • Web客户端...
  • 图片框.LoadAsync()

如果您的<!>“主<!>”; thread是Windows消息泵(GUI)线程,然后您可以使用Forms.Timer进行轮询 - 根据您需要让GUI线程“通知”工作线程中的数据的速度来调整计时器间隔。

如果您要使用List<>,请记住同步对共享foreach的访问权限,以避免CollectionModified例外。

我在实时交易应用程序中使用这种技术进行所有市场数据驱动的GUI更新,并且它运行良好。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top