1

I'm currently trying to implement a real-time multithreading software in C#. I need 3 threads. Every thread execution has to be finished before a deadline (500µs / 100µs / 50µs). The threads must run parallel during the whole runtime (until the user shuts down the program).

Is there a mecanism that can guarantee that the thread execution will not pass the deadline?

Here is my code :

static void Main(string[] args)
{
    Thread thread1 = new Thread(FirstThread);
    Thread thread2 = new Thread(SecondThread);
    Thread thread3 = new Thread(ThirdThread);

    thread1.start();
    thread2.start();
    thread3.start();
}

static void FirstThread()
{
    while(true)
    {
        SleepMicroSec(500);
    }
}

static void SecondThread()
{
    while(true)
    {
        SleepMicroSec(100);
    }
}

static void ThirdThread()
{
    while(true)
    {
        SleepMicroSec(50);
    }
}

private static void SleepMicroSec(long microSec)
{
    var sw = Stopwatch.StartNew();

    while (sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)) < microSec)
    {

    }
}

I expect the scheduler to be able to perform the context switching if the Task deadline is reached.

Thanks in advance for your answers !

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
bgabriel
  • 15
  • 6
  • 1
    Just to be clear, if the deadline isnt met, do you want to cancel the task? – nalnpir May 21 '19 at 13:23
  • The only way to "guarantee" is to abort each thread if its limit is reached and it is still running. That may not be advisable in lots of cases... – Peter B May 21 '19 at 13:24
  • I don't want to cancel the task, I just want to switch the context to run another task – bgabriel May 21 '19 at 13:29
  • @bgabriel `I don't want to cancel the task, I just want to switch the context to run another task.` So if task A is still running and it's time to start task B, you don't want to abort or kill task A, you want to start task B, running both task A and B at the same time? – Patrick Tucci May 21 '19 at 13:37
  • @Patrick Tucci the Tasks should be executed one after another. The only thing that matters is that they are not executed for a bigger period than the deadline – bgabriel May 21 '19 at 13:43
  • @bgabriel that part is clear. What is not clear is what you mean by context switching. Many threads can be executing at once in .Net. By using the term "context switch," do you mean you want to suspend execution on the current thread and start the next? If so, why? – Patrick Tucci May 21 '19 at 14:03
  • Doing near-hard-real-time work in C# is hard. You need to do things like juggle "no GC regions" and possible balance multiple thread pools. It's just about impossible to guarantee hard time constraints while working in a managed/GCed environment like the .NET Framework. If you have enough slop, you can get away with it, but if your specs are too tight (like perhaps: _"Every thread execution has to be finished before a deadline (500µs / 100µs / 50µs)."_), then your efforts are likely doomed – Flydog57 May 21 '19 at 14:51
  • Is it acceptable to have three threads running concurrently, but **not the same** three threads during the whole runtime? – Theodor Zoulias May 21 '19 at 16:45
  • There is no reliable mechanism to achieve what you want. You can explicitly switch context from the executing thread but there is no way to do it outside of the thread. At maximum you can set some check points inside the thread where you can check a signal from a "scheduler" but note that a thread can do some computations which it has no access to inject the check points to suspend or interrupt, thus there is no guarantee that a thread execution doesn't cross a deadline. – Dmytro Mukalov May 21 '19 at 19:12

1 Answers1

-1

Here is a method that invokes repeatedly an action in a background thread, aborting and restarting the thread every time the deadline is passed. It also accepts a CancellationToken to allow for premature cancellation of the procedure (before the end of the program).

private static void RepeatInBackgroundThread(Action action, int timeout,
    CancellationToken cancellationToken)
{
    var timer = new System.Timers.Timer(timeout);
    timer.AutoReset = false; // to raise the Elapsed event only once
    var thread = new Thread(() =>
    {
        while (true)
        {
            if (cancellationToken.IsCancellationRequested) return;
            timer.Start();
            action();
            timer.Stop();
        }
    });
    timer.Elapsed += (sender, e) =>
    {
        thread.Abort();
        thread.Join(); // Wait for the thread to die
        if (cancellationToken.IsCancellationRequested) return;
        RepeatInBackgroundThread(action, timeout, cancellationToken);
    };
    thread.IsBackground = true;
    thread.Start();
}

Usage example:

var random = new ThreadLocal<Random>(() => new Random());
var cts = new CancellationTokenSource();
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 1000)), 500, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 200)), 100, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 100)), 50, cts.Token);
//cts.CancelAfter(10000);

It should be noted that aborting threads is not a good practice in general.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104