【问题标题】:Questions related to Threadpool C#. Failure to complete execution of one thread与 Threadpool C# 相关的问题。未能完成一个线程的执行
【发布时间】:2014-03-06 10:13:53
【问题描述】:

我在下面有这个功能,我想了解这一点。另外,如果您有任何文件指向我。我从 msdn 阅读了有关 ManualResetEvent 和 ThreadPool 的信息

public void GetParametersThreadPool()
{
    var toProcess = 50;
    ManualResetEvent[] threadsActive = new ManualResetEvent[50];
    for (int handleIndex = 0; handleIndex < 50; ++handleIndex)
    {
        threadsActive[handleIndex] = new ManualResetEvent(false);

        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
            {
                string reportUrl = TeamFoundationTestConfig.TeamFoundationReportPath("TaskGroupStatus");
                ReportUri reportUri = ReportUri.Create(reportUrl);
                Log.Message(TraceEventType.Information, "ReportUri = {0}".InvariantFormat(reportUri.UriString));
                IList<Parameter> parameters = this.RemoteReportingServiceFactory.CreateReportParameterProvider().GetParameters(reportUri, SessionContext);
                Assert.IsNotNull(parameters, "Assertion failed: Parameters cannot be null. GetParameters failed");
                Assert.IsTrue(parameters.Count > 0, "Assertion failed: No parameters available on the report page. GetParameters failed. Count = {0}".InvariantFormat(parameters.Count));
                if (Interlocked.Decrement(ref toProcess) == 0)
                {
                    threadsActive[handleIndex].Set();
                }
            }), null);

        //// Wait for all the threads to complete before starting the next set of requests.
        threadsActive[handleIndex].WaitOne(); 
    }   
}

当我更新这行代码时:ManualResetEvent[] threadsActive = new ManualResetEvent[100];它给出了一个例外,说小于 64。

目前,当我运行此压力测试时,它挂在我进行日志记录的行上并且没有完成运行。我究竟做错了什么?

如果有更好的方法来做到这一点?也只是为了提供信息,我引用了 stackoverflow 中的另一个问题来自己创建这个函数

C# Execute Method (with Parameters) with ThreadPool

【问题讨论】:

  • 这个项目代码还是单元测试?

标签: c# multithreading threadpool stress-testing


【解决方案1】:

根据您的 .NET 版本,您可能希望使用 TaskTask.WaitAll(..),它随 .NET 4 一起提供。您的工具包中还有 CountdownEvent

使用任务通常很简单

var t = Task.Factory.StartNew(() => { your code });
t.Wait();

如果出于任何原因无法选择任务并行库,您可能需要考虑使用Semaphores(.NET 4 中的SemaphoreSlim)。

至于 64 位限制,这是操作系统强制执行的限制;可悲的是没有办法解决它。

【讨论】:

  • 如果我想并行调用同一个函数大约 100 次,它在哪里定义?
  • 我不确定我是否理解正确,但是使用for-Loop 初始化Task[] array = new Task[100](或List&lt;Task&gt;)并没有错; Task.WaitAll(array); 会等待。
  • @Markus,你的意思是t.Wait(),而不是t.WaitOne()
  • @avo,是的,感谢您指出。典型的凌晨 3 点错误。
  • 任务[] listOfTask = new Task[100]; for (int i = 0; i { }); } Task.WaitAll(listOfTask);
【解决方案2】:

按照建议,如果可以,您应该使用 Tasks。在它们可用之前,只需两个 WaitHandles 就可以做你想做的事。不是每个线程使用一个 WaitHandle,而是为所有线程使用一个 WaitHandle。等待线程计算 WaitHandle 发出信号的次数,并仅在收到所有信号后才继续。

【讨论】:

  • 技术上这不是信号量吗?
  • @Markus,在我看来并非如此。我没有看到如何使用 Semaphore 对象来实现相同的目的。也就是说,我从未真正使用过信号量,所以也许我遗漏了一些东西。
  • 信号量初始化为负值的问题,true;这在 C# 中是不可能的。一种解决方法是使用计数N0 空闲容量初始化信号量(即使其“满”),一旦工作完成,让每个工作线程Release() 在信号量上等待任务WaitOne() N次。
【解决方案3】:

WaitOne 阻塞当前线程,直到当前 WaitHandle 接收到信号,你正在编写多线程代码但这个方法实际上是同步方法

创建一个跟踪正在运行的任务数量的变量:

var toProcess = 50;

创建一个信号而不是数组

   ManualResetEvent signal = new ManualResetEvent(false);

for (int handleIndex = 0; handleIndex < 50; ++handleIndex)
    {


        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
            {
                string reportUrl = TeamFoundationTestConfig.TeamFoundationReportPath("TaskGroupStatus");
                ReportUri reportUri = ReportUri.Create(reportUrl);
                Log.Message(TraceEventType.Information, "ReportUri = {0}".InvariantFormat(reportUri.UriString));
                IList<Parameter> parameters = this.RemoteReportingServiceFactory.CreateReportParameterProvider().GetParameters(reportUri, SessionContext);
                Assert.IsNotNull(parameters, "Assertion failed: Parameters cannot be null. GetParameters failed");
                Assert.IsTrue(parameters.Count > 0, "Assertion failed: No parameters available on the report page. GetParameters failed. Count = {0}".InvariantFormat(parameters.Count));
                if (Interlocked.Decrement(ref toProcess) == 0)
                {
                    signal.Set();
                }
            }), null);


    }   

    signal.WaitOne();

不要将 signal.WaitOne() 放在 for 循环中,这会阻塞线程。

最后,如果您正在使用 .net 3.5 或更高版本,请考虑使用 Task

【讨论】:

  • 感谢分享我的方法中的缺陷。我放弃了你 1 找到它。也感谢您对使用 Task 的建议
猜你喜欢
  • 2012-05-02
  • 1970-01-01
  • 2023-03-27
  • 2021-06-21
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多