Is there a way to be notified (e.g. via an event or a callback) whenever a new ThreadPool thread is created?
I'm working on a .net console app that is using pjlib library via P/Invoke. This library requires that every thread that uses any of its APIs has to be previously registered via pj_thread_register API:
Register a thread that was created by external or native API to PJLIB. This function must be called in the context of the thread being registered. When the thread is created by external function or API call, it must be 'registered' to PJLIB using pj_thread_register(), so that it can cooperate with PJLIB's framework. During registration, some data needs to be maintained, and this data must remain available during the thread's lifetime.
When trying to call any pjlib function form an unregistered thread the library will indeed assert with the message:
Calling pjlib from unknown/external thread. You must
register external threads with pj_thread_register()
before calling any pjlib functions.
Now, the application's business logic uses async and await, and being it a console app the SynchronizationContext is null, meaning all continuations will run on ThreadPool's threads, including the P/Invokes calls to pjsip APIs, making necessary to call pj_thread_register() before every call to any of the pjsip APIs, to be sure that a newly created ThreadPool's thread won't try to use any pjsip API before registering itself.
I thought that if I could be notified (with a callback that gets called in the context of the newly created thread) whenever a new threadpool thread is created I could use this callback to register the new thread only once.
Is there a way to receive such a notification?
Alternatively I could use a SynchronizationContext (e.g. Stephen Cleary's AsyncContext or Stephen Toub's AsyncPump) on the main or on some dedicated threads (and register them as soon as I create them), but this would mean to redesign the application, maybe going towards an actor model, is there an alternative approach to face this kind of situations?
It might be possible to use profiling APIs or ETW to detect all thread pool creation events. I'm not sure how easy it would be to execute code in the context of that thread as a result of those events, though.
I would recommend using a [ThreadStatic] static bool PjInitialized; field in your interop layer, and add a check to every call at that layer. If it's not initialized, then call pj_thread_register before the actual call.
Related
I have a use case where I need to log data to file Asynchronously which I do not see it possible with Microsoft.Extensions.Logging so need your help to figure out the best solution
Use Seri ILogger interface, which according to this github doc does not seem to be using async await implementation but rather uses a background worker thread.
The wrapped sink (File in this case) will be invoked on a worker thread while your application's thread gets on with more important stuff.
Write My Custom Logger which utilizes TextWriter.Synchronized and WriteLineAsync
OR if there is any other solution which I am not aware of
It's normal for logging to use a background thread so it can expose a synchronous logging API. If all logging APIs were asynchronous, then that would force practically every method to be asynchronous.
Logging synchronously to a background thread also enables buffering and batched writes, which increase performance.
So I have an async grpc C# server that needs to do a lot of cross talk between server methods (eg, a streaming response value for a stream rpc could be generated from another rpc).
I have tried setting the SynchronizationContext to a single thread based context, but server methods still seem to be called from arbitrary threads.
How could I ensure that all server methods are called on the same thread, with async/await continuations also on the same thread?
For example, see the following RPC handler:
public override Task<ResponseProto> TestRpc(RequestProto request, ServerCallContext context)
{
// Call shared instance method - could be called from
// multiple concurrent grpc requests, or streamed responses etc
SharedInstanceMethod();
// This is different every call... making a cross-thread issue
// when calling SharedInstanceMethod();
int threadId = Thread.CurrentThread.ManagedThreadId;
}
Note that in this example, SharedInstanceMethod() is a placeholder for a lot of other functions and other asynchronous events - I'm not looking to make SharedInstance thread safe.
To get continuations to run on the same thread, you could use JoinableTaskFactory.Run(() => ...) from vs-threading, which sets a SynchronizationContext to achieve this.
A problem with this is that as soon as you hit a .ConfigureAwait(false) you will lose this context, and continuations will end up running back on the thread pool threads, so if you are calling 3rd party libraries then you cannot guarantee this behavior, and if they are following best practice, then they will likely be using .ConfigureAwait(false).
But going back to your question, I don't think this is what you want. It sounds like you don't have an asynchronous workflow that needs to be forced to run synchronously on 1 thread (which is good, cause it's not ideal). You have a method that cannot be called concurrently and needs some synchronization around it, you should use lock and add a private static object field to lock on.
When I received an exception that is related with thread context, I use delegate function and I invoke this delegate function. It is necessary for use control from an other thread. But I've just learned that I can use SynchronizationContext.Post() function and I can call my delegate in this method.
I'm not sure which one is better? What are differences between these methods?
It is the same thing, SynchronizationContext.Post() calls BeginInvoke() and Send() calls Invoke().
The key property of SynchronizationContext is that there is more than one implementation of it. Important ones are WindowsFormsSynchronizationContext, it uses Control.Begin/Invoke and DispatcherSynchronizationContext, it uses Dispatcher.Begin/Invoke. There are others for ASP.NET, Windows Store (aka WinRT, aka Universal) apps, out-of-process servers that are COM+ hosted, etcetera.
The extra level of indirection helps avoid taking a dependency on the specific method that invokes. Important for any class library of course.
Control.Invoke is equivalent to SynchronizationContext.Send in that both are synchronous. Control.BeginInvoke is equivalent to SynchronizationContext.Post in that both are asynchronous. Use any of these 4 methods to prevent a cross-thread exception.
Use SynchronizationContext to encapsulate thread marshaling code. For example, Form1 creates object Worker to do some work on a different thread. The constructor for Worker captures the current (i.e. Form1's) SynchronizationContext. When Worker produces data to display on Form1, Worker can use the captured SynchronizationContext to synchronize to Form1's thread before sending a notification, e.g. event, to Form1. This means that Form1 does not need to know about the different thread, does not need to call InvokeRequired, and has less code. It also means that Worker does not need to know that its client is a Form.
Below is an excellent series explaining SynchronizationContext:
Understanding SynchronizationContext - Part I
Understanding SynchronizationContext - Part II
Understanding SynchronizationContext - Part III
I have a C# library that would like to have the ability to Send/Post work to the "main" ui thread (if one exists).
This library may be used by:
A winforms application
A native application (with UI)
A console application (with no UI)
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization, that will allow me to (at a later time) Send/Post work to the main thread (if the main thread has that ability--i.e. it has a message pump). For example, the library would like to put up some Winforms UI on the main thread if and only if the main application has the ability for me to get to the main thread.
Things I've tried:
A SynchronizationContext:
Capturing this works fine for a Winforms application (a WindowsFormsSynchronizationContext will be installed as the Current SynchronizationContext. This also works fine for the console app--since I can detect that the Current SynchronizationContext is null (and thus, know that I don't have the ability to send/post work to the main thread). The problem here is the native UI application: It has the ability (i.e. it has a message pump), but the Current Synchronization context is null and thus I can't differentiate it from the Console app case. If I could differentiate, then I could simply install a WindowsFormsSynchronizationContext on the main thread, and I'm good to go.
A Dispatcher: Capturing this using Current creates a new SynchronizationContext. Thus, in all situations I will get back a Dispatcher. However, for a Console app, using Dispatcher.Invoke from a background thread will hang (as expected). I could use Dispatcher.FromThread (which doesn't create a Dispatcher for the thread if one doesn't exist). But the native UI application will return a null Dispatcher using this method, and so then I'm, again, stuck not being able to distinguish the UI application from the console application.
A TaskScheduler: I could use FromCurrentSynchronizationContext. This has the same problems as the SynchronizationContext. I.e. Before calling FromCurrentSyncronizationContext, I'd have to check if the Current SynchronizationContext is null (which will be the case for the Console app and the native ui application). So, again I can't distinguish the native ui application from the console application.
I, of course, could have the user of my library specify whether or not it is a UI application when they call my Initialize method, but I was hoping to avoid that complication for the user of the library if possible.
This is not in general possible, a library that's apt to be used in threads cannot make any assumptions about which particular thread is the UI thread. You can capture Synchronization.Current but that will only work correctly if your initialization method is called from the UI thread. That's not terribly unusual to work out well, like TaskScheduler.FromCurrentSynchronizationContext() tends to work by accident, but not a guarantee. You can add a check, if Thread.CurrentThread.GetApartmentState() doesn't return STA then the odds that you are not being called from the UI thread are very high. SynchronizationContext.Current will also often be null in that case, another way to check.
The (arguably) better ways are to just not worry about it and let the client code figure it out, it won't have any trouble marshaling the callback. Or to expose a property of type SynchronizationContext so that the client code can assign it. Or add it as a constructor argument. Throw an InvalidOperationException if you are ready to Post but find out that it is still null, that's an oversight that the client programmer only makes once.
I think you should make this an option to your Initialize method (or somehow allow your caller to request UI interaction), to me that just makes more sense. I don't know the specifics but these seems to me to be a "courteous" thing to do, let your caller decide if they want you to or want to support your UI. I would take it one step further and even as the caller to supply a synchronization context. But that's my opinion.
To answer your question, there are a few "hacks" you can use to determine if you're running in a console applicaiton. This SO question has some information on that: C#/.NET: Detect whether program is being run as a service or a console application
Change the library initialization to have a SyncronizationContext parameter. If the parameter is null then the library doesn't need to do anything special, if not null Post/Send GUI updates there.
I think this is exactly what AsyncOperationManager.CreateOperation() is for.“Implementing the Event-based Asynchronous Pattern” states:
The Event-based Asynchronous Pattern provides a standardized way to package a class that has asynchronous features. If implemented with helper classes like AsyncOperationManager, your class will work correctly under any application model, including ASP.NET, Console applications, and Windows Forms applications.
It is up to the caller to decide if they want to call your API on the UI thread or not. If they do, this will capture the context and events will go through the message pump in order. In a Console application you can get the same behavior if you install a SynchronizationContext such you get for free by using AsyncContext.Run() from the Nito.AsyncEx nuget package. No need for an extra property or to have to write the conditional code yourself. If no serializing synchronization context is available, AsyncOperation.Post() will use the fake synchronization context available to Console apps which just queue the event to the threadpool instead (meaning that the posts may not execute in order). Just remember to call AsyncOperation.OperationCompleted() or AsyncOperation.PostOperationCompleted() when done.
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization
This is exactly what AsyncOperationManager.CreateOperation() does, and in an environment-agnostic way. But you should try to pair this with a call to OperationCompleted() which maybe would be more difficult given the API you want to expose. The easiest way to use AsyncOperation would be to start an operation when your library actually starts an operation instead of during initialization. Or by having the initialization routine return an IDisposable context object handle which would signal to the consumer that they need to manage its lifetime.
We're working with a 3rd-party legacy system that requires thread affinity for some of the tear-down logic. We're also hosting a WCF service inside IIS which, under heavy loads will do a rude unloading of our app domain. In these cases it falls to the critical finalizer to do cleanup. Unfortunately, without thread affinity in the finalizer, the 3rd-party system deadlocks.
So roughly:
public class FooEnvironment : CriticalFinalizerObject, IDisposable
{
public FooEnvironment()
{
// start up C API
}
public bool Dispose()
{
// shutdown C API (from same thread ctor was called on)
}
~FooEnvironment()
{
// try to shutdown C API but deadlock!
}
}
I've tried various things where we Run with the ExecutionContext from the initializing thread, but this doesn't work (at least in IIS) and we get an invalid operation exception stating that this execution context can't be used (ostensibly because it may have been marashalled across AppDomains, which seems likely).
I've read several things basically stating that what I'm trying to do can't be done but I figured I would ask since there isn't a lot of information on this topic.
Back in the old days I developed a library that wrapped the hideous DDEML which is a Win32 api wrapper around the DDE protocol. The DDEML has thread affinity requirements as well so I feel your pain.
The only strategy that is going to work is to create a dedicate thread that executes all of your library calls. This means biting the bullet and marshaling every single request to call into this API onto this dedicated thread and then marshaling back the result to the original thread. It sucks and its slow, but it is the only method guaranteed to work.
It can be done, but it is painful. You can see how I tackled the problem in my NDde library. Basically, the finalizer will simply post a message via static method calls to a thread that can accept and dispatch them to the appropriate API call. In my case I created a thread that called Application.Run to listen for messages because DDE required a Windows message loop anyway. In your case you will want to create the thread in a manner that monitors a custom message queue. This is not terribly difficult if you use the BlockingCollection class because the Take method blocks until an item appears the queue.