1

I can't figure out how to do this in a good way.

Basically, I have a program with two key tasks that contain loops that it runs over and over until the user clicks the stop button.

Pseudo code:

  1. Task A is started: a while loop that does work continuously
  2. Task B is started: a System.Timers.Timer that checks continuously for a specific condition
  3. If Task B finds the condition to be true, it should temporarily stop Task A, and do a bunch of work
  4. Once Task B is done with that work it should allow Task A to start looping again, and go back to checking for the specific condition

This then all continues in perpetuity (until user clicks stop button and the program ends).

When I made the first iteration of the program I basically created two separate threads, and then just had bools in the loops that i used for cancellation. So, Task B just set the bool in Task A to be false and used a Thread.Join() to wait until Task A had completely finished before it started doing its work. Once Task B was done, it created Task A on a completely new thread again. This seemed highly inefficient, as there is no reason I should really have to end the thread, when all I want to do is just halt it until Task B is done.

I have been reading up on async ops through Task Parallel Library (async-await), and thought I could perhaps use cancellation tokens instead of the bools, but it looks like once a task is cancelled with cancellation token the token cannot be reset and task cannot be restarted.

In any case, how would you build this?

i3arnon
  • 113,022
  • 33
  • 324
  • 344
Anders
  • 580
  • 8
  • 17

2 Answers2

1

Create an object to be used for locking. Put the working part of both task A and B inside a lock statement on this object. Make sure you lock inside the loop of thread A, so that you give B a chance to acquire the lock too, between iterations. This way, only one thread may enter the locked region at a time. Thread A doesn't have to be stopped, it will continue running when B is finished. (You could also use wait handles, or mutexes, or whatever really, it's the most basic case of mutual exclusion.)

fejesjoco
  • 11,763
  • 3
  • 35
  • 65
  • Thanks guys. Fejesjoco, is that similar to @L.B's suggestion? Are these types of classes/patterns obsolete now that Task asynchrony is out there? I am a bit confuised as someone once told me that a lot of the original threading is now outdated with all the new task asynchronous functionality out there... – Anders Nov 23 '14 at 17:24
  • Forgot to ask: 1) Would you use Tasks instead of Threads for any of this? 2) Would you use cancellation tokens to cancel the loops in the threads/tasks, once the user clicks stop button? (http://msdn.microsoft.com/en-us/library/dd997364.aspx) – Anders Nov 23 '14 at 17:33
  • I wouldn't use tasks for continuously running jobs, threads are perfect for that, but that's just an opinion. Unless a .NET class is officially obsoleted, there's nothing wrong with using it under the right circumstances. Cancellation tokens are perfect for stopping threads. – fejesjoco Nov 23 '14 at 17:39
  • Got it, thanks a lot. I could mark the task as longrunning to avoid using the thread pool, but i def have to look into regular mutual exclusion, as I jumped straight to asynchronous programming before really learning old school threading first... – Anders Nov 23 '14 at 17:45
  • @fejesjoco: this would be a good answer, worthy of an up-vote, except for two problems: you didn't show any code example, and the statement that the object reference should be `static`. Just as a question should include a code example, so too should an answer (even if the question failed to). And whether the locking object should be referenced by a `static` field or not depends entirely on whether the code that uses it is `static` or not (which we don't know here). – Peter Duniho Nov 23 '14 at 19:19
  • @PeterDuniho I removed the static part, that was just out of habit/experience, but I don't understand your other comment. He asked a theoretical question, I gave a theoretical answer. I suggested the lock keyword exactly because it's so simple and it's part of the C# syntax. I really wonder what added value would it have, just typing a keyword? OP obviously knows enough not to need that. How could I provide a meaningful example if there was no code in the question? I'm totally confused why you would mention it. – fejesjoco Nov 23 '14 at 19:35
  • Sorry if my suggestion isn't clear. My point is this: your answer takes the form of describing how one would write some code. But _actual code_ is a much better way to express something like that. Even if the code is simple and can't include specific details of the actual operations (since the OP failed to provide those), a code example is far more useful and less ambiguous than an English-language description of that code. – Peter Duniho Nov 23 '14 at 19:42
1

To do that in a truly async-await fashion you shouldn't block threads or have them in a state of busy-wait (looping constantly until some condition changes) because it's synchronous and wastes resources. You should use async synchronization objects.

In your case you can have an AsyncLock to handle the mutually exclusive part (making sure only one worker runs at the same time) and an AsyncAutoResetEvent to notify the second worker of the condition change.

Unfortunately the .Net Framework doesn't yet have a built-in implementation for AsyncLock or AsyncAutoResetEvent, but the Visual Studio SDK does (or you can implement them yourself, like I did).

Community
  • 1
  • 1
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • Thanks l3arnon, I will look into this once I have successfully implemented the blocking approach. To avoid the spinner (looping until condition change), I am using a Timer. That is pretty efficient. The other loops do work in each loop. – Anders Dec 09 '14 at 19:50