简体   繁体   中英

Wait for all Threads

I have a little problem with Threads in this code..

I just want to run a lot of tasks together, and continue when all of them finish.

while (true)
{
    //   Run tasks together:
    foreach (object T in objectsList)
    {
        if (T.something>0)
            var task = Task.Factory.StartNew(() => T.RunObject());
            task.ContinueWith(delegate { ChangeObject(T, 1); }, TaskContinuationOptions.NotOnFaulted);
    }
    //   <-- Here I want to wait for all the task to be finish.
    //   I know its task.Wait() but how to waitAll()?
    System.Threading.Thread.Sleep(this.GetNextTime()); 
    var RefreshObjects = new Task(loadObjectsList); RefreshObjects .Start(); RefreshObjects.Wait();
}

I don't know how many objects will be in objectsList and I don't know if T.something will be > 0. so I can't just use:

Task[] Tasks = new Task[objectsList.count()]
for (int T=0; T<objectsList.count(); ++T)
{
    if (objectsList[T].something>0)
        var task = Task.Factory.StartNew(() => objectsList[T].RunObject());
        task.ContinueWith(delegate { ChangeObject(objectsList[T], 1); }, ...);
}
Task.WaitAll(Tasks);

Because Tasks will contains nulls when objectsList[T].something!>0 ...

Thanks for any advice!

Just switch the condition and create a List of tasks only for the objects which matches your criteria.

var tasks = objectsList
            .Where(x => x.Something() > 0)
            .Select(x => {
                            var task = Task.Factory.StartNew(() => x.RunObject());
                            task.ContinueWith(t => ChangeObject(....));
                            return task;
                         })
            .ToArray();

    Task.WaitAll(tasks);

Your code sample just waits for RunObject() to complete! If this is desired skip the rest of my answer. If you want to wait for the continuation to complete, too you can use this

var tasks = objectsList
            .Where(x => x.Something() > 0)
            .Select(x => Task.Factory.StartNew(() => x.RunObject()).ContinueWith(t => ChangeObject(....)))
            .ToArray();

    Task.WaitAll(tasks);

because ContinueWith generates a new Task.

If objectsList implements IEnumerable, (as an array does), (And there are less than 64 objects in the list), you can use this:

public delegate void SyncDelegatesInParallelDelegate<in T>(T item);
public static class ParallelLinqExtensions
{
    public static void SyncDelegatesInParallel<T>(
        this IEnumerable<T> list, 
        SyncDelegatesInParallelDelegate<T> action)
    {
        var foundCriticalException = false;
        Exception exception = null;
        var waitHndls = new List<WaitHandle>();

        foreach (var item in list)
        {
            // Temp copy of session for modified closure
            var localItem = item;
            var txEvnt = new ManualResetEvent(false);

            // Temp copy of session for closure
            ThreadPool.QueueUserWorkItem(
                 depTx =>
                 {
                     try { if (!foundCriticalException) action(localItem); }
                     catch (Exception gX) 
                     { exception = gX; foundCriticalException = true; }
                     finally { txEvnt.Set(); }
                 }, null);
            waitHndls.Add(txEvnt);
        }
        if (waitHndls.Count > 0) WaitHandle.WaitAll(waitHndls.ToArray());
        if (exception != null) throw exception;
    }
}

you would call it like this

 objectsList.SyncDelegatesInParallel(delegate { ChangeObject(T, 1);});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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