简体   繁体   English

C#等待所有线程完成执行

[英]C# Wait Till All Threads Complete Execution

I've tried this... 我试过这个......

public ArrayList GetAllObjectAttributes()
    {
        List<Task> taskList = new List<Task>();
        ArrayList allObjectAttributes = new ArrayList();
        taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder));}));
        taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)); }));
        taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)); }));
        taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)); }));
        Task.WaitAll(taskList.ToArray());
        return allObjectAttributes;
    }

and this... 和这个...

public ArrayList GetAllObjectAttributes()
    {
        Thread[] threads = new Thread[4];
        ArrayList allObjectAttributes = new ArrayList();
        threads[0] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder)));
        threads[1] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)));
        threads[2] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)));
        threads[3] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)));

        foreach(Thread thread in threads)
        {
            thread.Start();
            thread.Join();
        }
        return allObjectAttributes;
    }

and this too... 这也是......

public ArrayList GetAllObjectAttributes()
    {
        Thread[] threads = new Thread[4];
        ArrayList allObjectAttributes = new ArrayList();
        threads[0] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder)));
        threads[1] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)));
        threads[2] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)));
        threads[3] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)));

        foreach(Thread thread in threads)
        {
            thread.Start();
        }
        while(threads[0].IsAlive || threads[1].IsAlive || threads[2].IsAlive || threads[3].IsAlive)
        {
            Thread.Sleep(500);
        }
        return allObjectAttributes;
    }

I also tried Spawn Multiple Threads for work then wait until all finished 我也试过Spawn Multiple Threads工作然后等到所有完成

I still get a null in one of the arraylist items in allObjectAttributes. 我仍然在allObjectAttributes中的一个arraylist项中得到null。

However, when I do 但是,当我这样做的时候

public ArrayList GetAllObjectAttributes()
    {
        ArrayList allObjectAttributes = new ArrayList();
        allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder)));
        allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)));
        allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)));
        allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)));
        return allObjectAttributes;
    }

I never get a null item in the arraylist items. 我从来没有在arraylist项目中获得null项。

  1. What am i doing wrong to wait until all threads complete? 等到所有线程完成后我做错了什么?
  2. Any other advise, so that the arraylist is returned only after all the 4 threads complete execution. 任何其他建议,以便只有在所有4个线程完成执行后才返回arraylist。
private List GetObjectAttributes(TreeViewAttrs tv)
{
    List objectAttributes = new List();
    string command = "COMMAND_TO_EXECUTE";
    if (command != "")
    {
        List results = RunCommand(command);
        if (results == null) { return null; }
        if (results.Count > 0)
        {
            foreach (string result in results)
            {
                if (!result.Contains("" + tv + ""))
                {
                    string[] res = reformatResponseString(result); //reformat the strings as per custom structure
                    if (res != null) { objectAttributes.Add(res); }
                }
            }
            return objectAttributes;
        }
    }
    return null;
}

Slightly improved by using a thread-safe collection (.NET 4.0 compatible): 使用线程安全集合(.NET 4.0兼容)稍微改进:

List<Task> taskList = new List<Task>();
ConcurrentBag<object> allObjectAttributes = new ConcurrentBag<object>();

taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder))));
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile))));
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile))));
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent))));

Task.WaitAll(taskList.ToArray());

return allObjectAttributes;

Alternative approach: use Task.Result once all tasks have completed (thread-safe collection no longer required as only one thread modifies ArrayList ): 替代方法:完成所有任务后使用Task.Result (不再需要线程安全集合,因为只有一个线程修改了ArrayList ):

Task<object>[] taskList = {
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.Folder)),
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.XMLFile)),
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.TextFile)),
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.Parent))
};

Task.WaitAll(taskList);

ArrayList allObjectAttributes = new ArrayList();

foreach (Task<object> task in taskList) {
    allObjectAttributes.Add(task.Result);
}

return allObjectAttributes;

Significantly improved by using Task.WhenAll (.NET 4.5 only): 使用Task.WhenAll (仅限.NET 4.5) 显着改进:

object[] allObjectAttributes = await Task.WhenAll(
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.Folder)),
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.XMLFile)),
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.TextFile)),
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.Parent))
);

return allObjectAttributes;

*Note: I used object as the generic parameter as you left the return type of GetObjectAttributes unspecified. *注意:我使用了object作为通用参数,因为你保留了未指定的GetObjectAttributes的返回类型。

Task.WaitAll() that you used in your first example should work as intended. 您在第一个示例中使用的Task.WaitAll()应该按预期工作。 However, I suspect that the issue you're having has to do more with thread safety of the collection you use, ArrayList, rather than the fact that the completion of all task is not waited upon. 但是,我怀疑你所拥有的问题必须使用你使用的集合的线程安全性,ArrayList,而不是等待所有任务的完成这一事实。 ArrayList offers no thread safety, so you should look at other ways, either through use of a locking mechanism or through the use of a thread-safe collection, such as ConcurrentBag ( https://msdn.microsoft.com/en-us/library/dd381779(v=vs.110).aspx ). ArrayList没有线程安全性,所以你应该通过使用锁定机制或通过使用线程安全的集合来查看其他方法,例如ConcurrentBag( https://msdn.microsoft.com/en-us/ library / dd381779(v = vs.110).aspx )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM