Set property value when all threads are completed?

There are three threads in my application, for example:

private Thread _analysisThread; private Thread _head2HeadThread; private Thread _formThread; 

and each thread starts as follows:

 if (_analysisThread == null || !_analysisThread.IsAlive) { _analysisThread = new Thread(() => { Analysis.Logic(match); }); _analysisThread.Start(); } 

I have a ListView where the user can select an item and then start the stream again, but I want this to not make the methods inside each stream heavy, so it takes time to complete them.

So far, I want to disable ListView selection, so I did:

 <ListView IsEnabled="{Binding IsMatchListEnabled}"> private bool _isMatchListEnabled = true; public bool IsMatchListEnabled { get { return _isMatchListEnabled; } set { _isMatchListEnabled = value; OnPropertyChanged(); } } 

before starting Thread IsMatchListEnabled = false; : IsMatchListEnabled = false; but I need to check if the whole thread is completed, and then do: IsMatchListEnabled = true; , in fact, if I turn on the ListView after all the threads, I get the ListView even on, because the Thread code is asynchronous, and the code outside Thread is synchronization, so this property is actually useless.

I tried to avoid this by creating an infinite loop like this:

 while (true) { if (!_analysisThread.IsAlive && !_head2HeadThread.IsAlive && !_formThread.IsAlive) { IsMatchListEnabled = true; break; } } 

this loop is placed after all threads have completed, but as you can imagine, this will freeze the application. Any solution?

+4
source share
2 answers

All comments are correct - it is better to use Tasks . Just to answer the OP question.

You can synchronize threads with ManualResetEvent , having an array of events by the number of threads and one additional thread to change IsMatchListEnabled when all threads are complete.

 public static void SomeThreadAction(object id) { var ev = new ManualResetEvent(false); events[id] = ev; // store the event somewhere Thread.Sleep(2000 * (int)id); // do your work ev.Set(); // set the event signaled } 

Then in another place we need to initialize the wait procedure.

 // we need tokens to be able to cancel waiting var cts = new CancellationTokenSource(); var ct = cts.Token; Task.Factory.StartNew(() => { bool completed = false; while (!ct.IsCancellationRequested && !completed) { // will check if our routine is cancelled each second completed = WaitHandle.WaitAll( events.Values.Cast<ManualResetEvent>().ToArray(), TimeSpan.FromSeconds(1)); } if (completed) // if not completed, then somebody cancelled our routine ; // change your variable here }); 

A complete example can be found and viewed here .

+2
source

I would suggest using the Microsoft Reactive Framework for this. It is more powerful than tasks, and the code is much simpler than using threads.

Let's say you have 3 long actions:

 Action huey = () => { Console.WriteLine("Huey Start"); Thread.Sleep(5000); Console.WriteLine("Huey Done"); }; Action dewey = () => { Console.WriteLine("Dewey Start"); Thread.Sleep(5000); Console.WriteLine("Dewey Done"); }; Action louie = () => { Console.WriteLine("Louie Start"); Thread.Sleep(5000); Console.WriteLine("Louie Done"); }; 

Now you can write the following simple query:

 IObservable<Unit> query = from a in new [] { huey, dewey, louie }.ToObservable() from u in Observable.Start(() => a()) select u; 

You run it as follows:

 Stopwatch sw = Stopwatch.StartNew(); IDisposable subscription = query.Subscribe(u => { }, () => { Console.WriteLine("All Done in {0} seconds.", sw.Elapsed.TotalSeconds); }); 

The received results:

  Huey start
 Dewey start
 Louie start
 Huey done
 Louie done
 Dewey done
 All Done in 5.0259197 seconds.

Three 5-second actions completed in 5.03 seconds. Everything is parallel.

If you want to stop the calculation earlier, just call subscription.Dispose() .

NuGet "System.Reactive" to get a bit.

+1
source

Source: https://habr.com/ru/post/1273073/


All Articles