首页 文章

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

提问于
浏览
3

我试过这个......

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;
    }

还有这个...

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;
    }

这也是......

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;
    }

我也试过Spawn Multiple Threads for work then wait until all finished

我仍然在allObjectAttributes中的一个arraylist项中得到一个null .

但是,当我这样做的时候

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;
    }

我从来没有在arraylist项目中得到一个空项目 .

  • 等到所有线程完成后我做错了什么?

  • 任何其他建议,以便仅在所有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;
}

2 回答

  • 7

    您在第一个示例中使用的Task.WaitAll()应该按预期工作 . 但是,我怀疑你所遇到的问题必须更多地使用你使用的集合的线程安全性,ArrayList,而不是等待所有任务完成的事实 . ArrayList不提供线程安全性,因此您应该通过使用锁定机制或通过使用线程安全集合(例如ConcurrentBag(https://msdn.microsoft.com/en-us/library/dd381779(v=vs.110).aspx))来查看其他方法 .

  • 0

    使用线程安全集合(.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;
    

    替代方法:完成所有任务后使用 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 使用 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;
    

    *注意:我使用了 object 作为通用参数,因为你留下了 GetObjectAttributes 未指定的返回类型 .

相关问题