0

I am trying to reuse two threads in a while loop like this:

while (condition)
            {
                thread1.Start();
                thread1.Join();
                thread2.Start();
            }

I am using thread1.Join() because I want thread2 to wait for the first's thread's finalization. However, after thread1 runs one time I get the error: 'Thread is running or terminated; it cannot restart.' From what I read, a thread can only be started once so that would imply that threads in loops are just impossible to work but I would guess that there is a way somehow.

One thing that I forgot to mention is that each thread requires input from the keyboard so it should work like this: thread1 runs -> input from the keyboard -> thread 2 runs -> input from the keyboard.

Last Update: I made it work using this:

int i= 0;
while(condition)
            {
                thread1[i] = new Thread(() => player1Turn(ref creditP1, ref positionP1, ref creditP2, propertyPrices, playerProperty));
                thread1[i].Start();
                thread1[i].Join();

                thread2[i] = new Thread(() => player2Turn(ref creditP2, ref positionP2, ref creditP1, propertyPrices, playerProperty));
                thread2[i].Start();
                thread2[i].Join();

                i++;
            }

I know this is a horrible implementation because I use a bunch of threads but for now it will do. I will surely look into Thread pooling as many of you said. Thanks for your time!

  • 2
    C# has a feature call a Threadpooling that is likely a much better option here. Use threads from the pool and let the framework worry about managing them between each iteration. Additionally, to coordinate between the two thread tasks inside each iteration you are likely much better off using the same thread in an asynchronous manner via the new-ish `async` and `await` keywords. – Joel Coehoorn May 02 '22 at 16:26
  • As per above comment by Joel C, you should use Thread pool. But for your learning purpose, if you did `thread1= new Thread()`, then your looping would still work. – Anand Sowmithiran May 02 '22 at 16:47
  • Thank you, Joel, I will look into that. Anand, the looping works indeed if I do that but each thread require me to input something from the keyboard and if I do what you said it will just screw up everything. I need to code to do this: thread1 starts -> I input something from the keyboard; thread2 starts -> I input something from the keyboard and repeat until the condition is met. – ronnietheman May 02 '22 at 17:17
  • I think that would work only if I did not have to input something from the keyboard in each thread. – ronnietheman May 02 '22 at 17:47

2 Answers2

1

You could consider using Microsoft's Reactive Framework (NuGet "System.Reactive") to get access to the EventLoopScheduler class. Each instance of this class creates a single thread that you can schedule code to run on - either immediately or by a scheduled time.

In your case you can hand code off from one instance of the EventLoopScheduler to another. It might be a little more convoluted than a simple while loop, but it should let you do what you want.

I've created an example to show what can be done. I'm implemented the below function, processing even numbers of one EventLoopScheduler and odd numbers on another. When I get a value of 1 I stop.

function

Here's the code:

var els1 = new EventLoopScheduler();
var els2 = new EventLoopScheduler();

int value = 15;

void Execute()
{
    if (value != 1)
    {
        if (value % 2 == 0)
        {
            els2.Schedule(() =>
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: {value}");
                value = value / 2;
                els1.Schedule(Execute);
            });
        }
        else
        {
            Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: {value}");
            value = value * 3 + 1;
            els1.Schedule(Execute);
        }
    }
    else
        Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: {value}");
}

els1.Schedule(Execute);

When the value is even I can els2.Schedule(() => and at the end of that call I pass back to els1.Schedule(() => to complete the call. This just continues to recursively call itself until the function computes a 1.

Here's a typical run:

22: 15
37: 46
22: 23
37: 70
22: 35
37: 106
22: 53
37: 160
37: 80
37: 40
37: 20
37: 10
22: 5
37: 16
37: 8
37: 4
37: 2
22: 1

Note the hand-off two the two threads. Evens run on thread 37 and odds on thread 22.

You should call .Dispose() on each EventLoopScheduler to allow the threads to terminate.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

Once a thread starts, it cannot be restarted:

https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.start?view=net-6.0

Once the thread terminates, it cannot be restarted with another call to Start.

As Joel Coehoorn mentioned, a better approach is to use a ThreadPool.

beautifulcoder
  • 10,832
  • 3
  • 19
  • 29