I have an application, which has run without issue for a long time, which suddenly fails to start due to the following error:

"This property has already been set and cannot be modified."

When I inspect the code, which basically resembles the snippet below, I see the exception is thrown on the line which attempts to name the first task inside Parallel.Invoke

Thread.CurrentThread.Name = "Main Program Thread";

// Do some start up tasks in parallel
Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = 10 },
() =>
{
    Thread.CurrentThread.Name = "First thread";
},
() =>
{
    Thread.CurrentThread.Name = "Second thread";
});
                        ...

Obviously the cause of this must be that the main thread already has a name, and the first task is being run on the main thread rather than a threadpool thread.

Whilst I can resolve this by not naming the threads inside Parallel.Invoke, I am curious as to why this has suddenly started happening. Is it the case that normally Parallel.Invoke() previously ran all its tasks on threadpool threads and for some reason is unable to do so anymore? What could trigger this sort of thing?

The more I look at this code the more perplexed I am that it has ever worked. It looks to me like this code should always throw an exception.

3

There are 3 best solutions below

0
usr On

Parallel usually runs some work on the thread-pool and some on the current thread in order to not let it sit idle. This is not guaranteed, all work can run on the pool or on the current thread.

I don't know what happens when you assign a name to a pool thread. Either it throws, does nothing or works once. None of that is desirable.

Throw this code away. Don't mess with threads you don't own.

You can use the LongRunning task option to get dedicated threads that you can configure.

6
Luaan On

Thread-pool threads are reused. The thread a threadpool task runs on does not belong to you. What you're doing is explicitly forbidden, so do not be surprised when it explodes in your face.

Apart from that, Parallel.Invoke is perfectly within it's reasonable operating parameters when it runs some of its code on the same thread it's called from - there's no point in just waiting for all the other threads to finish, and wasting a perfectly fine thread.

0
JMc On

I uninstalled .NET 4.6 and this code began to work again. There must be an optimisation in Parallel.Invoke in newer versions of the framework which exposed the bug in our code where it never manifest before.