Maximilian Eheim
Maximilian Eheim

Reputation: 3

How to achieve sequential blocking behavior in multithread application?

I'm writing an application that should simulate the behavior of a PLC. This means I have to run several threads making sure only one thread at a time is active and all others are suspended. For example:

The highest priority is to complete the tasks before they are called again, otherwise I have to react, therefore a thread that should be blocked should not run until a certain point, otherwise multicore processing would elaborate the code and only wait to pass the results.

I read several posts and learned that Thread.suspend is not recomended and semaphore or monitor operations mean that the code is executed until a specific and fixed point in the code while I have to pause the threads exactly where the execution has arrived when an other thread (with higher "priority") is called.

I also looked at the priority setting but it doesn't seem to be 100% relevant since the system can override priorities.

Is there a correct or at least solid way to code the blocking mechanism?

Upvotes: 0

Views: 534

Answers (2)

Leonard Klausmann
Leonard Klausmann

Reputation: 215

I hope I don't missunderstand your question :)

One possibility to your problem might be to use a concurrent queue: https://msdn.microsoft.com/de-de/library/dd267265(v=vs.110).aspx

For example you create a enum to control your state and init the queue:

 private ConcurrentQueue<Action> _clientActions ;
     private enum Statuskatalog
      {
           Idle,
           Busy
       };

Create a timer to start and create a timerfunktion.

Timer _taskTimer = new Timer(ProcessPendingTasks, null, 100, 333);



private void ProcessPendingTasks(object x)
         {
           _status = Statuskatalog.Busy;
             _taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
             Action currentTask;
             while( _clientActions.TryDequeue( out currentTask ))
             {
                 var task = new Task(currentTask);
                 task.Start();         
                 task.Wait();
             }

         _status=Statuskatalog.Idle;
         }

Now you only have to add your tasks as delegates to the queue:

_clientActions.Enqueue(delegate { **Your task** });
            if (_status == Statuskatalog.Idle) _taskTimer.Change(0, 333);

On this base, you can manage your special requirements you were asking for.

Hope this was, what you were searching for.

Upvotes: 1

Luaan
Luaan

Reputation: 63772

I don't think you need to burden yourself with Threads at all. Instead, you can use Tasks with a prioritised TaskScheduler (it's not too hard to write or find by googling).

This makes the code quite easy to write, for example the highest priority thread might be something like:

while (!cancellationRequested)
{
  var repeatTask = Task.Delay(130);

  // Do your high priority work      

  await repeatTask;
}

Your other tasks will have a similar basic layout, but they will be given a lower priority in the task scheduler (this is usually handled by the task scheduler having a separate queue for each of the task priorities). Once in a while, they can check whether there is a higher priority task, and if so, they can do await Task.Yield();. In fact, in your case, it seems like you don't even need real queues - that makes this a lot easier, and even better, allows you to use Task.Yield really efficiently.

The end result is that all three of your periodic tasks are efficiently run on just a single thread (or even no thread at all if they're all waiting).

This does rely on coöperative multi-tasking, of course. It's not really possible to handle full blown real-time like pre-emption on Windows - and partial pre-emption solutions tend to be full of problems. If you're in control of most of the time spent in the task (and offload any other work using asynchronous I/O), the coöperative solution is actually far more efficient, and can give you a lot less latency (though it really shouldn't matter much).

Upvotes: 1

Related Questions