使用ThreadPool.QueueUserWorkItem对线程进行排序

时间:2009-12-02 15:35:04

标签: c# concurrency multithreading

我是线程基础知识的新手。

我有一个要对XML文件执行的操作队列(节点添加,节点删除等)

1]有'n'xml文件,并且对于每个文件,使用分配来自线程池的线程 ThreadPool.QueueUserWorkItem来做那些文件操作。

我希望使用线程实现并发和操作顺序(重要)     例如:假设是否要对文件“A.xml”执行操作[a1,a2,a3,a4,a5]
    和操作[b1,b2,b3,b4,b5,b6,b7]将在文件“B.xml”上执行.....
我想分配线程,以便我可以在执行这些操作 相同的顺序,也同时(因为文件不同)。

2]也可以为每个操作分配一个线程并实现可靠性并保持顺序。

在STA模型中,我做了类似的事情......

while(queue.count>0){
  File f = queue.Dequeue(); //get File from queue       
  OperationList oprlst = getOperationsForFile(f); 
// will get list-> [a1,a2,a3,a4,a5]   
  for each Operation oprn in oprlst 
  {
    performOperation(f,oprn)
    //in MTA i want to wait till operation "a1" completes and then operation "a2" will
   //start.making threads wait till file is in use or operation a(i) is in use.
  }    
}

我想与操作订单保存同时执行此操作。 线程(操作)可以在一个文件上等待......但是 不同的操作需要不同的执行时间。

我尝试了AutoResetEvent和WaitHandle.WaitAll(..)但是它做了while循环 停止直到所有'a(i)'操作结束......我希望a(i)和b(j)同时执行。 (但在(i)和b(j)中排序)

目前正在使用.net 2.0。

这非常相似,是Question

提出的问题的一部分

3 个答案:

答案 0 :(得分:5)

为每个文件创建一个新线程,或者只为每个文件使用一个 ThreadPool.QueueUserWorkItem调用 - 无论哪种方式,您希望按顺序依次执行文件操作,因此,为该部分使用多个线程毫无意义。在您的情况下,唯一可用的并行性是跨越不同的文件,而不是操作。

答案 1 :(得分:2)

您应该避免在Monitor线程中使用WaitHandle锁和ThreadPool结构等线程阻塞技术,因为这些线程被其他进程使用。您需要使用基于单个文件的线程。如果单个文件没有花费那么长时间来处理(并且您没有太多文件),那么ThreadPool将起作用。

ThreadPool实现

你可以在以文件为中心的方法上使用EnqueueUserWorkItem ......就像这样:

private void ProcessFile(Object data)
{ 
    File f = (File)data;

    foreach(Operation oprn in getOperationsForFile(f))
    {
        performOperation(f, oprn);
    }
}

然后在处理文件的代码中,执行以下操作:

while(queue.Count > 0)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), queue.Dequeue());
}

如果您需要阻止调用线程直到它们全部完成,那么WaitHandle就可以了(因为您阻止了自己的线程, ThreadPool线)。但是,您必须创建一个小的有效负载类来将其传递给线程:

private class Payload
{
    public File File;
    public AutoResetEvent Handle;
}

private void ProcessFile(Object data)
{ 
    Payload p = (Payload)data;

    foreach(Operation oprn in getOperationsForFile(p.File))
    {
        performOperation(f, oprn);
    }

    p.Handle.Set();
}

...

WaitHandle[] handles = new WaitHandle[queue.Count];
int index = 0;

while(queue.Count > 0)
{        
    handles[index] = new AutoResetEvent();

    Payload p = new Payload();

    p.File = queue.Dequeue();
    p.Handle = handles[index];

    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), p);

    index++;
}

WaitHandle.WaitAll(handles);

线程实现

但是,如果您有大量文件(或者文件可能需要花费大量时间来处理),那么创建自己的线程是个更好的主意。这也可以让您省略WaitHandle s。

private void ProcessFile(File f)
{     
    foreach(Operation oprn in getOperationsForFile(f))
    {
        performOperation(f, oprn);
    }

    p.Handle.Set();
}

private object queueLock = new object();

private void ThreadProc()
{
    bool okToContinue = true;

    while(okToContinue)
    {
        File f = null;

        lock(queueLock)
        {
            if(queue.Count > 0) 
            {
                f = queue.Dequeue();
            }
            else
            {
                f = null;
            }
        }

        if(f != null)
        {
            ProcessFile(f);
        }
        else
        {
            okToContinue = false;
        }
    }
}

...

Thread[] threads = new Thread[20]; // arbitrary number, choose the size that works

for(int i = 0; i < threads.Length; i++)
{
    threads[i] = new Thread(new ThreadStart(ThreadProc));

    thread[i].Start();
}

//if you need to wait for them to complete, then use the following loop:
for(int i = 0; i < threads.Length; i++)
{
    threads[i].Join();
}

前面的示例是一个非常基本线程池,但它应该说明需要做什么。

答案 2 :(得分:0)

线程用于可以异步完成的操作,并且您希望同步完成操作。处理文件似乎可以异步(多线程)完成。

相关问题