ArrayList的.NET并行处理

35g0bw71  于 2023-03-09  发布在  .NET
关注(0)|答案(3)|浏览(108)

我第一次尝试嵌入多线程,遇到了一些意想不到的问题,希望你能帮忙。
下面是给我带来麻烦的代码片段:

ArrayList recordsCollection = new ArrayList();
ArrayList batchCollection = null;
int idx = 0;

while(true)
{
  // Some code to generate and assign new batchCollection here
  recordsCollection.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate
  {
    ProcessCollection(recordsCollection.GetRange(idx, 1));
  });
  Interlocked.Increment(ref idx);
}

private void ProcessCollection(ArrayList collection)
{
   // Do some work on collection here
}

一旦调用了ProcessCollection方法,并且我试图迭代集合,我就会得到“底层列表中的范围无效”。
先谢了!
更新:伙计们,谢谢你们每一个人。通过应用你们的建议,我能够大大简化并让它工作。

mrphzbgm

mrphzbgm1#

在这里使用Interlocked.Increment是不必要的,您希望局部变量idx只被一个线程看到,这样就不需要加锁。
当前您正在“关闭循环变量”,这意味着线程看到的是变量的最新值,而不是创建委托时的值。您希望其他线程接收此变量的 * 副本 *。这样,即使原始变量更改,这些副本也不会更改。
尝试将代码更改为:

int j = idx;
ThreadPool.QueueUserWorkItem(delegate
{
    ProcessCollection(recordsCollection.GetRange(j, 1));
});

相关问题

xzlaal3s

xzlaal3s2#

你有几个问题。

  • 正如Mark指出的,您正在捕获一个循环变量,这将真正混淆这里的事情。
  • 您在不使用同步机制的情况下,一边修改集合,一边阅读集合。

我假设您已经省略了获取batchCollection然后定期从recordsCollection中删除它们的代码,否则那里也会有问题。
以下是您可以修复它的方法。

ArrayList recordsCollection = new ArrayList();  
ArrayList batchCollection = null;  
int idx = 0;  

while(true)  
{  
  lock (recordsCollection) 
  {
    recordsCollection.Add(batchCollection);  
  }

  int capturedIndex = idx; // Used for proper capturing.

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ArrayList range;
    lock (recordsCollection)
    {
      range = recordsCollection.GetRange(capturedIndex, 1);
    }
    ProcessCollection(range);  
  });  

  idx++;
}

或者我的重构版本,据我所知,做了完全相同的事情...

List<List<Record>> recordsCollection = new ArrayList();  
List<Record> batchCollection = null;  

while(true)  
{  
  recordsCollection.Add(batchCollection);

  List<List<Record>> range = new List<List<Record>>();
  range.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ProcessCollection(range);  
  });      
}
mw3dktmi

mw3dktmi3#

你这是在玩火。你有一个开放的结局,看:http://en.wikipedia.org/wiki/Closure_(computer_science)
另外,如果只获取一个项目,为什么要使用getRange?
使用通用列表也会有所帮助。

private void wee()
    {
        List<List<string>> recordsCollection = new List<List<string>>();

        //int idx = 0;

        while(true)
        {
            //scope the batchcollection here if you want to start a thread with an anonymous delegate
            List<string> batchCollection = null;
            // Some code to generate and assign new batchCollection here
            recordsCollection.Add(batchCollection);

              ThreadPool.QueueUserWorkItem(delegate
              {
                  ProcessCollection(batchCollection);
              });
              //Interlocked.Increment(ref idx);
        }
    }
    private void ProcessCollection(List<string> collection)
    {
        // Do some work on collection here
    }

如果我错了请纠正我,但是我认为您不再需要idx变量了。
另外,不要忘记异常是由调用堆栈引发的:http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx
干杯!

相关问题