C# Waiting for Multiple Threads to Finish

C# Waiting for multiple threads to finish

List<Thread> threads = new List<Thread>();
foreach (cpsComms.cpsSerial ser in availPorts)
{
Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev));
t.Start((object)ser);//start thread and pass it the port
threads.Add(t);
}
foreach(var thread in threads)
{
thread.Join();
}

Edit

I was looking back at this, and I like the following better

availPorts.Select(ser =>
{
Thread thread = new Thread(lookForValidDev);
thread.Start(ser);
return thread;
}).ToList().ForEach(t => t.Join());

C# Wait Till All Threads Complete Execution

Slightly improved by using a thread-safe collection (.NET 4.0 compatible):

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<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):

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.

C# wait for all threads to finish in Main()

Perhaps Thread.Join() is what you're looking for?

you also might find this article usefull.

Create multiple threads and wait for all of them to complete

It depends which version of the .NET Framework you are using. .NET 4.0 made thread management a whole lot easier using Tasks:

class Program
{
static void Main(string[] args)
{
Task task1 = Task.Factory.StartNew(() => doStuff());
Task task2 = Task.Factory.StartNew(() => doStuff());
Task task3 = Task.Factory.StartNew(() => doStuff());

Task.WaitAll(task1, task2, task3);
Console.WriteLine("All threads complete");
}

static void doStuff()
{
//do stuff here
}
}

In previous versions of .NET you could use the BackgroundWorker object, use ThreadPool.QueueUserWorkItem(), or create your threads manually and use Thread.Join() to wait for them to complete:

static void Main(string[] args)
{
Thread t1 = new Thread(doStuff);
t1.Start();

Thread t2 = new Thread(doStuff);
t2.Start();

Thread t3 = new Thread(doStuff);
t3.Start();

t1.Join();
t2.Join();
t3.Join();

Console.WriteLine("All threads complete");
}

C# .Net Wait for all threads to complete and get return values

Try using a Task<string> instead of a Task and querying the Task<string>.Result

Waiting for threads to complete

DISCLAIMER: I posted this answer only because it does what the OP asked for and I didn't take the answer from Servy: there's nothing that you can do. But I advice to NOT use this in a production environment. Personally I would ditch that library and implement it myself.

This said, as a test I created a class library that holds a method DoWork which starts a background thread that runs for 10 seconds:

public class ThirdParty
{
public static void DoWork()
{
new Thread(() => Thread.Sleep(10000)) { IsBackground = true }.Start();
}
}

Now, the idea is to compare the running threads before and after the ThirdParty.DoWork call. After the call, one (or more) thread-id's will be collected and translated into thread handle(s) by using OpenThread. At the end, you can call WaitForMultipleObjects to wait until the third party background thread has finished doing its work.

class Program
{
[DllImport("kernel32.dll")]
static extern uint WaitForMultipleObjects(int nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds);

[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, int dwThreadId);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

const uint SYNCHRONIZE = 0x00100000;

static IntPtr GetThreadHandleById(int threadId)
{
return OpenThread(SYNCHRONIZE, false, threadId);
}

static void Main(string[] args)
{
var threads = new List<int>();
foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
threads.Add(thread.Id);

ThirdParty.DoWork();

var threadHandlesToWaitFor = new List<IntPtr>();
foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
if (!threads.Contains(thread.Id))
threadHandlesToWaitFor.Add(GetThreadHandleById(thread.Id));

Console.WriteLine("Waiting for {0} thread(s) to finish...", threadHandlesToWaitFor.Count);
WaitForMultipleObjects(threadHandlesToWaitFor.Count, threadHandlesToWaitFor.ToArray(), true, 0xffffffff);

foreach (var handle in threadHandlesToWaitFor)
CloseHandle(handle);
}
}

In essence, we're waiting for an unmanaged thread that seems to run the spawned managed thread. This can break in the future because .NET does not guarantee that every managed thread runs on its own unmanaged thread.

Wait multiple threads for one result

Finally I ended with the following solution:

private class RequestHandler
{
private EventWaitHandle _handle;

public RequestHandler(Func<string> request)
{
_handle = new EventWaitHandle(false, EventResetMode.ManualReset);
Start(request);
}

private void Start(Func<string> doRequest)
{
Result = doRequest();
_handle.Set();
}

public void WaitForResponse()
{
_handle.WaitOne();
}

public string Result { get; private set; }
}

private Object _lockObject = new Object();
private Dictionary<string, RequestHandler> _pendingRequests = new Dictionary<string, RequestHandler>();

public string GetCustomer(int id)
{
RequestHandler request;

lock (_lockObject)
{
if (!_pendingRequests.TryGetValue(id, out request))
{
request = new RequestHandler(() => LoadEntity(id));
_pendingRequests[id] = request;
}
}

request.WaitForResponse();
lock (_lockObject)
{
_pendingRequests.Clear();
}
return request.Result;
}

Although it is still possible to have duplicated posts to the server this is a very minimal chance (on thread deletes all the pending requests after the first thread created a request and before a second thread tries to get the same customer data).

Thanks to the inspiration the posts here gave.

C# Wait for signals from all the threads before proceed

Your code is prone to race conditions. After all threads have completed the first iteration, all events are still set; if a single thread then runs through the loop before the others get to reset their events, it'll see the other events still set, and stop waiting early.

There's plenty of ways to resolve this bug, but the best solution for you is System.Threading.Barrier (also see Threading objects and features with section about Barrier). It's explicitly designed for this situation, where you want multiple threads to work in parallel through a multi-step algorithm.



Related Topics



Leave a reply



Submit