In a process with many async threads, I set each thread to a specific name and monitor it regularly to see its status. Some threads seem to regularly lose their name value though. I can't find out why this happens.
public static void ChangeThreadName(this Thread current, string newName)
{
if (string.IsNullOrEmpty(current.Name))
{
try
{
current.Name = newName;
}
catch (InvalidOperationException ex)
{
Log.Error(ex, $"Error when trying to change Threadname from [{current.Name}] to [{newName}]");
}
}
else
{
Log.Warning($"Trying to change Threadname from [{current.Name}] to [{newName}]");
}
}
Inside a while loop of an async task:
if (Thread.CurrentThread.ManagedThreadId != originalID)
{
Log.Verbose($"Thread change detected at ThreadHandler{QueueID}-{threadNumberString}, oldID = {originalID} - newID = {Thread.CurrentThread.ManagedThreadId}");
nr = await ThreadManager.ReRegisterProc(nr, threadName, false);
originalID = Thread.CurrentThread.ManagedThreadId;
}
if (Thread.CurrentThread.Name != threadName)
{
Log.Verbose("ThreadName changed to {status} -> reverting to {args}", Thread.CurrentThread.Name, threadName);
Thread.CurrentThread.ChangeThreadName(threadName);
}
Renaming and reregistering the task works, but I'd prefer it not being necessary.
I tried adding the threads to a static list and looping it to see it's status, this doesn't work without reregistering as shown above.
EDIT:
It is now clear that monitoring threads might not be the way to go. However i still need to know which of all async threads are actually running and which are waiting. It regards a large variety of different threads which are created in classes that operate independent from eachother.
I currently use this code:
public partial class ThreadManagement
{
private SemaphoreSlim KeySemaphore { get; } = new(1, 1);
public async Task<List<Thread>> GetThreads()
{
await Task.CompletedTask;
return TheseProcThreads.Values.ToList();
}
public async Task<Thread?> GetSpecificThread(long key)
{
if (TheseProcThreads.TryGetValue(key, out Thread FoundThread))
{
await Task.CompletedTask;
return FoundThread;
}
else
{
await Task.CompletedTask;
return null;
}
}
public async Task<long> TryAddProc(long key, Thread value)
{
if (!TheseProcThreads.TryAdd(key, value))
{
key = await TryAddProc(await GetNewKey(), value);
}
return key;
}
public async Task<long> TryAddProc(long key, Thread value, string newName, ThreadPriority prio, bool background = false)
{
value.ChangeThreadName(newName);
value.Priority = prio;
value.IsBackground = background;
return await TryAddProc(key, value);
}
public async Task<long> TryAddProc(Thread value)
{
return await TryAddProc(await GetNewKey(), value);
}
public async Task<bool> TryRemoveProc(long key)
{
if (!TheseProcThreads.TryRemove(key, out _))
{
Log.Error("{object} {actie} {args} {status}.", "Thread", "verwijderen", "uit dictionary","mislukt");
await Task.CompletedTask;
return false;
}
await Task.CompletedTask;
return true;
}
public async Task<long> ReRegisterProc(long nr, string methodName, bool background)
{
Thread.CurrentThread.ChangeThreadName(methodName);
try
{
Thread.CurrentThread.IsBackground = background;
}
catch (Exception Ex)
{
Log.Error(Ex, "{actie} {object} {status}", "Instellen", "thread background", "mislukt");
}
await TryRemoveProc(nr);
return await TryAddProc(Thread.CurrentThread);
}
public async Task<long> GetNewKey()
{
await KeySemaphore.WaitAsync();
await StaticKeySemaphore.WaitAsync();
long tmpKey = TheseProcThreads.Count + 2;
while (true)
{
if (ReservedKeys.Contains(tmpKey))
{
tmpKey++;
}
else
{
break;
}
}
ReservedKeys.Add(tmpKey);
KeySemaphore.Release();
StaticKeySemaphore.Release();
return tmpKey;
}
}
public partial class ThreadManagement
{
private static SemaphoreSlim StaticKeySemaphore { get; } = new(1, 1);
private static ConcurrentDictionary<long, Thread> TheseProcThreads { get; } = new();
private static List<long> ReservedKeys { get; } = new();
}