【问题标题】:Why the counter does not work in threadpool为什么计数器在线程池中不起作用
【发布时间】:2020-03-28 13:19:23
【问题描述】:

我使用线程池做了一个简单的应用程序,但是当我在线程池内部或外部进行计数器时,它在所有情况下都只返回零或非连续数字?

我的程序 [我正在发送 10000 个有价值的 webrequest [API],我知道线程池更快的方式吗? 因为我想在 5 到 10 分钟内发送和接收 10,000 个请求。 ]

    public int Count;

    private void TaskCallBack(Object ThreadNumber)
    {
        MessageBox.Show(Count.ToString());  

        Interlocked.Increment(ref Count);
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            //// Queue the task.
            for (int x = 0; x < 10; x++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(TaskCallBack));
            }

            this.Count = 0;
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error : " + ex);
        }
    }

【问题讨论】:

  • 尝试在this.Count = 0; 和MessageBox.Show(Count.ToString()); 上添加断点。
  • 您将 Count 的值分配为 0。您可能希望在第一行将 Count 初始化为 0 并删除该行:this.Count = 0;
  • 我试过了brakpoint,循环后同样的错误还是0
  • 经典线程竞赛错误,这个重复得很好。您无法以足够快的速度单击 10 个确定按钮以让所有 10 个线程都进入 Increment() 调用。之后没有人仍然调用 Count.ToString()。 Interlocked 类不能替代lock。

标签: c# multithreading threadpool threadpoolexecutor


【解决方案1】:

好吧,您可以让 10 个线程在其中任何一个线程递增该值之前都打印出 Count 的初始值。如果线程在其他线程调用Show 之前递增Count,也不能保证连续顺序。要同时获得两者,请使用互斥锁来控制对回调逻辑的并发访问:

    public int Count;
    private readonly object _countLock = new Object();

    private void TaskCallBack(Object ThreadNumber)
    {
        lock( _countLock )
        {
            ++Count;
            MessageBox.Show(Count.ToString());
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            // this smells
            this.Count = 0;

            //// Queue the task.
            for (int x = 0; x < 10; x++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(TaskCallBack));
            }

        }
        catch (Exception ex)
        {
            MessageBox.Show("Error : " + ex);
        }
    }

【讨论】:

  • 同样的问题,我有数组列表,我希望这个计数从 0 移动到 10
  • 号码排列与否无所谓,重要的是不要重复并且在10个号码之内
  • @hashembaddad 我认为如果您仍然遇到问题,您需要显示更多代码
【解决方案2】:

当您使用Interlocked 类来操作变量时,对这个变量的所有访问都必须通过Interlocked 类来完成。否则无法保证您将获得变量的当前值。所以,对于初学者来说,Count 变量不应该变成public。

private int _count;

public int Count => Interlocked.CompareExchange(ref _count, 0, 0);

private void TaskCallBack(Object ThreadNumber)
{
    var localCount = Interlocked.Increment(ref _count);
    MessageBox.Show(localCount.ToString());
}

【讨论】:

  • 附带说明,从 UI 线程以外的任何线程调用 MessageBox 类是一个坏主意。使用BackgroundWorker 只是在ThreadPool 中安排一些工作也是一个坏主意。通常,不建议在牢牢掌握概念之前进行多线程处理。有太多事情可能出错。
  • 谢谢,我尝试了这个,但是当我将数组列表索引设置为计数器时,我尝试了同样的错误,每次都给我同样的东西 [0]
猜你喜欢
  • 1970-01-01
  • 2013-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2022-01-10
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
相关资源
最近更新 更多