【问题标题】:Mimic "Invoke" / "BeginInvoke" Style Method Call on Custom Class/Method在自定义类/方法上模仿“Invoke”/“BeginInvoke”样式方法调用
【发布时间】:2023-03-27 23:00:03
【问题描述】:

我想创建一个线程安全的方法,我可以从多个工作人员调用而不会阻塞工作线程。我还希望代码简洁得像 InvokeRequired->BeginInvoke 类型代码用于 UI 控件...当然,在这种情况下我没有使用 Control,该方法位于自定义类上。我也不一定要对每种方法都这样做。那么这是否可以在自定义类/方法上轻松实现?

须藤代码:

class foo
{
    //Fields
    Context MyContext;
    List<T> UnsafeList = new List<T>();

    //Method
    public void MyMethod(int someArg, Item someOtherArg)
    {
        if (!MyContext)
        {
            MyContext.BeginInvoke(...);
            return; //Calling thread returns
        }
        else
        {
            UnsafeList.Add(someOtherArg);
            return; //MyContext Thread returns
        }
    }

    //Constructor
    public foo()
    {
        MyContext = new GetSomeThreadHandle();
    }
}

我想我知道如何使用自定义 EventArgs 做到这一点,但它涉及几乎重复的代码,我正在寻找更通用/更简洁的解决方案。

编辑

这是使用 C# .Net 4.0

【问题讨论】:

  • 目前还不清楚您真正想要实现的目标。你能把任务放在线程池上吗?另外,请说明您使用的是哪个版本的 .NET。
  • 基本上我想排队或序列化来自多个工作人员的操作而不阻塞工作人员。使用 WinForms .Net 4.0

标签: c# multithreading synchronization


【解决方案1】:

鉴于:

  • 您使用的是 .NET 4
  • 您提到了排队序列化请求...

...听起来你想要一个生产者/消费者队列,通过BlockingCollection&lt;T&gt;。启动一个将从队列中拉取的线程(消费者),然后从您的工作线程中添加到队列中。

您需要考虑如果队列达到意外/不希望的水平,您希望发生什么。 (你可以阻塞,你可以抛出一个异常,你可以放弃请求。)

编辑:有关详细信息,请参阅this MSDN blog post on BlockingCollection&lt;T&gt;

【讨论】:

  • 这个例子演示了这种方式blogs.msdn.com/b/csharpfaq/archive/2010/08/12/…
  • @Jon Skeet 嗯...简要阅读 MSDN,我可以排队 Action 代表吗?我希望不需要为我想要调用的每个真实方法都使用包装器方法,而是将它们全部包含在同一个方法中,就像调用 GUI 控件时一样。
  • 浏览博客文章,但不确定这是否有价值。
  • 这看起来更有希望 msdn.microsoft.com/en-us/library/dd997394.aspx 试图弄清楚如何使用它。
  • @JoshW:但你说你没有拥有控件……所以你没有 UI 线程来安排工作。是的,您可以将Action 代表排队 - 但您通常只需将输入排队等待处理任务。老实说,目前还真的不是很清楚你在做什么。
【解决方案2】:

展示应用于您的任务的生产者/消费者方式的小示例

public void produceConsume()
{
    var results = new BlockingCollection<double[]>();

    var producer = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 100; i++)
        {
            var data = new double[1024];
            results.Add(data);                    
        }

        results.CompleteAdding();
    });

    var consumer = Task.Factory.StartNew(() =>
    {
        foreach (var item in results.GetConsumingEnumerable())
        {
           // put in chart
        }
    });

    producer.Wait();
}

如果您需要多个消费者消耗所有数据,您也可以使用 ConcurrentQueue

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多