Cannot wait on a transparent proxy in ThreadPool nonblocking wait - c#

Can I somehow register nonblocking handler on marshalled signal in different app domain?
I have a class that cannot be MarhsalByRef, yet I need to be able to call a method A on in in a different app domain D and then method B in the same app domain D.
This is could be easily solved by MarshalByRef - but I cannot use due to other code.
So I use a simple marshallable event and signal to the other app domain. I'd want to register a nonblocking handler in the other app domain - but it doesn't seem possible. I'm left with active wait?
Below is the repro:
[Serializable]
//this cannot be MarshalByRefObject
public class AppDomainTest
{
private readonly ManualResetEvent _mrse = new ManualResetEvent(false);
public static void Test()
{
AppDomainTest ap = new AppDomainTest();
Task.Factory.StartNew(() => ap.CreateDomainAndRun());
Thread.Sleep(1000);
ap.CallIntoDomain();
}
public void CreateDomainAndRun()
{
var otherDomain = AppDomain.CreateDomain("MyDomain", AppDomain.CurrentDomain.Evidence);
Task.Run(() => otherDomain.DoCallBack(RunInternal));
}
public void CallIntoDomain()
{
this._mrse.Set();
}
private void RunInternal()
{
//----------- HERE IS THE REPRO ---------------- //
//This crashes
//"Cannot wait on a transparent proxy"
//ThreadPool.RegisterWaitForSingleObject(_mrse, CancellationCallBack, null,
// Timeout.InfiniteTimeSpan, true);
Task.Factory.StartNew(() =>
{
//This works just fine
_mrse.WaitOne();
CallIntoDomainInternal();
}, TaskCreationOptions.LongRunning).Wait();
}
private void CancellationCallBack(object state, bool timedOut)
{
CallIntoDomainInternal();
}
private void CallIntoDomainInternal()
{
Console.WriteLine($"App domain: {AppDomain.CurrentDomain.FriendlyName}");
}
}
Registering callback with ThreadPool throws 'Cannot wait on a transparent proxy'. Active wait in task works just fine.

Related

Azure Service Bus WinForms App - Not Receiving/Displaying Messages

I am trying to display messages to a list box in a WinForms application but it is not working. I am using the most recent Azure namespace, hence using asynchronous methods.
Below is Program.cs:
namespace App
{
public class Program
{
static ServiceBusClient client;
static ServiceBusProcessor processor;
public static List<string> data = new List<string>();
[STAThread]
public static async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
data.Add(body);
// complete the message. messages is deleted from the subscription.
await args.CompleteMessageAsync(args.Message);
}
public static void Main(string[] args)
{
Application.Run(new Form1());
}
public static async Task MainAsync()
{
client = new ServiceBusClient(_serviceBusConn);
// create a processor that we can use to process the messages
processor = client.CreateProcessor(_serviceBustopic, _ServiceBusSubscription, new ServiceBusProcessorOptions());
try
{
// add handler to process messages
processor.ProcessMessageAsync += MessageHandler;
// add handler to process any errors
processor.ProcessErrorAsync += ErrorHandler;
// start processing
await processor.StartProcessingAsync();
}
finally
{
await processor.DisposeAsync();
await client.DisposeAsync();
}
}
}
}
//end of Program.cs
And the Form.cs:
namespace App
{
public partial class Form1 : Form
{
public static List<string> AppNames = new List<string>();
public Form1()
{
InitializeComponent();
}
public static async Task receiveMessage()
{
await Program.MainAsync();
AppNames = Program.data;
}
public async void button1_Click(object sender, EventArgs e)
{
await receiveMessage();
for (int i = 0; i < AppNames.Count; i++)
{
listBox1.Items.Add("item" + AppNames[i].ToString());
}
}
}
}
There is a console version of this program that is functional, but I cannot seem to get it to display the messages in this Winforms Application. Some debugging showed me that the program was getting into the Main async. method upon the button being clicked, but it was not going into the Message Handler despite messages being sent through the service bus.
The pattern that you're using for the Service Bus client and processor isn't going to work in your scenario.
In MainAsync, when you call StartProcessingAsync, the method will return once the processor has started. Execution is then going to reach the finally block, where the processor and client are disposed. At that point, the processor is not running and, therefore, is not receiving messages.
Each time button1_Click runs, you're creating a new set of clients, establishing a new connection to Azure, and then immediately throwing them away.
The processor is intended to be a long-lived type that runs continuously in the background, calling back into your code as messages are available. Likewise, the client is intended to be used as a singleton for the lifetime of your application. I'd suggest reading through the Service Bus "Hello World" sample, which would help to explain some of the types and recommended patterns for use.

How do you get a working interaction with ConfigureAwait(true) in a console application?

In a small project i am working on i have the neccessity for a component to execute a components shutdown code in the same thread that it was initialized in. However unlike in WPF/Winforms/Web the synchronizationcontext which takes care of this does not work.
My guess is that the lack of a synchronization context is the issue that causes the lack of utilization for ConfigureAwait(true).
Does someone know how to properly implement this?
I read this article but could not make any sense of it yet. Perhaps it was too late yesterday.
Minimal Repro:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleSyncContext
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
await SomeBackgroundWorkAsync();
// if this is the same thread as above the question is solved.
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
}
private static async Task SomeBackgroundWorkAsync()
{
await Task.Run(() => { });
}
}
}
As you already figured out, console application by default doesn't have synchronization context, so ConfigureAwait has no effect, and continuation after your await SomePageLoad() will run on random thread pool thread. Note that using async main method is essentially equivalent to this:
static async Task AsyncMain() { ... } // your `async Task Main method`
// real Main method generated by compiler
static void RealMain() {
AsyncMain().GetAwaiter().GetResult();
}
In your case you don't need any synchronization context though. What you want is initialize CefSharp on main thread and shutdown CefSharp on main thread. So instead of using async Main - you can do the same as above, but initialize and shutdown Cef outside of async method:
static void Main(string[] args) {
// starting with thread 1
Cef.Initialize(new CefSettings());
try {
AsyncMain(args).GetAwaiter().GetResult();
}
finally {
// we are on main thread here
Cef.Shutdown();
}
}
static async Task AsyncMain(string[] args) {
await SomePageLoad(); // more stuff here
}
Edit: if you insist on using synchronization context then it can be done, but will add a lot of complications for nothing. Out goal is create synchronization context which will run all actions on the same thread. This case be done with simple actions queue, here is basic implementation (don't use it in production, provided as an example only, no exception handling and so on):
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
private readonly Thread _thread;
public CustomSyncContext() {
// start new thread which will handle all callbacks
_thread = new Thread(() => {
// set outselves as current sync context for this thread
SynchronizationContext.SetSynchronizationContext(this);
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
});
_thread.Start();
}
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void WaitForShutdown() {
_thread.Join();
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
And your code then becomes:
var ctx = new CustomSyncContext();
ctx.Send(async (_) => {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
ctx.Shutdown();
Console.WriteLine("done");
}
}, null);
ctx.WaitForShutdown();
Now your code runs on custom synchronization context, and continuation after await SomePageLoad(); will be posted to that synchronization context and executed by our thread (the same thread which inited CefSharp) (no ConfigureAwait(true) is needed, as it's already true by default). Note that we achieved nothing useful - we have one more thread, and our main thread is still blocked waiting for the whole operation to complete (there is no sensible way around that).
Edit 2: here is variation which does not require separate thread, but is not much better:
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void Start() {
// now we run the loop on main thread
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
static async Task Main(string[] args) {
var ctx = new CustomSyncContext();
// set sync context
SynchronizationContext.SetSynchronizationContext(ctx);
// now execute our async stuff
var task = DoStuff().ContinueWith(x => ctx.Shutdown());
// now run the loop of sync context on the main thread.
// but, how do we know when to stop? Something from outside should singal that
// in the case signal is completion of DoStuff task
// note that most of the time main thread is still blocked while waiting for items in queue
ctx.Start();
}
private static async Task DoStuff() {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
Console.WriteLine("done");
}
}
Your problem is indeed the lack of a Synchronisation context. You can't use ConfigureAwait(true) as this implies that you need to return to the original scheduler/context which does not exist.
Custom implementation
A very simple implementation that ought to do the trick is the one found here. Basically two steps.
Implement a custom synchronization context
public class CustomSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback action, object state)
{
SendOrPostCallback actionWrap = (object state2) =>
{
SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
action.Invoke(state2);
};
var callback = new WaitCallback(actionWrap.Invoke);
ThreadPool.QueueUserWorkItem(callback, state);
}
public override SynchronizationContext CreateCopy()
{
return new CustomSynchronizationContext();
}
public override void Send(SendOrPostCallback d, object state)
{
base.Send(d, state);
}
public override void OperationStarted()
{
base.OperationStarted();
}
public override void OperationCompleted()
{
base.OperationCompleted();
}
}
Initaliaze it and use it
static void Main()
{
var context = new CustomSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(context);
AsyncEx library
You can also use the AsyncEx library
private static void Main(string[] args)
{
AsyncContext.Run(() => AsyncMethod(args));
}
static async void AsyncMethod(string[] args)
{
await something().ConfigureAwait(true);
}

How to make sure that all the threads started by the test(s) are stopped before completion

I am building a windows service that communicates with other processes using named pipe.
My unit test for the named pipe communication is throwing this error message 4 times:
System.AppDomainUnloadedException: Attempted to access an unloaded
AppDomain. This can happen if the test(s) started a thread but did not
stop it. Make sure that all the threads started by the test(s) are
stopped before completion.
Here's my unit test:
[TestMethod]
public void ListenToNamedPipeTest()
{
var watcher = new ManualResetEvent(false);
var svc = new WindowService();
svc.ClientMessageHandler += (connection, message) => watcher.Reset();
svc.ListenToNamedPipe();
sendMessageToNamedPipe("bla");
var wait = watcher.WaitOne(1000);
svc.Dispose();
Assert.IsTrue(wait, "No messages received after 1 seconds");
}
private void sendMessageToNamedPipe(string text)
{
var client = new NamedPipeClient<Message, Message>(DeviceCertificateService.PIPE_NAME);
client.ServerMessage += (conn, message) => Console.WriteLine("Server says: {0}", message.Text);
// Start up the client asynchronously and connect to the specified server pipe.
// This method will return immediately while the client runs in a separate background thread.
client.Start();
client.PushMessage(new Message { Text = text });
client.Stop();
}
How do I make all threads stop before my unit test stops?
Thanks
UPDATE:
The named pipe client does not have a close() function:
// Type: NamedPipeWrapper.NamedPipeClient`2
// Assembly: NamedPipeWrapper, Version=1.5.0.0, Culture=neutral, PublicKeyToken=null
// MVID: D2B99F4D-8C17-4DB6-8A02-29DCF82A4118
// Assembly location: C:\Users\Thang.Duong\Source\Workspaces\Post Tracking System\Applications\Dev\OHD\packages\NamedPipeWrapper.1.5.0\lib\net40\NamedPipeWrapper.dll
using System;
namespace NamedPipeWrapper
{
public class NamedPipeClient<TRead, TWrite> where TRead : class where TWrite : class
{
public NamedPipeClient(string pipeName);
public void Start();
public void PushMessage(TWrite message);
public void Stop();
public void WaitForConnection();
public void WaitForConnection(int millisecondsTimeout);
public void WaitForConnection(TimeSpan timeout);
public void WaitForDisconnection();
public void WaitForDisconnection(int millisecondsTimeout);
public void WaitForDisconnection(TimeSpan timeout);
public bool AutoReconnect { get; set; }
public event ConnectionMessageEventHandler<TRead, TWrite> ServerMessage;
public event ConnectionEventHandler<TRead, TWrite> Disconnected;
public event PipeExceptionEventHandler Error;
}
}
My WindowsService inherits the ServiceBase class which has the Dispose() function to close all threads. That's why I get all racing errors.
I had to avoid calling Dispose() function and replace it with client.Close() and svc.Close() function. The svc.Close() function is my custom implementation to stop and close the named pipe server.

How to stop a service when a thread is doing work (without using Thread.Abort)

I have a service running some different tasks in a loop until the service is stopped.
However one of these tasks i calling a web service and this call can take several minutes to complete. I want to be able to stop the service instantly, 'cancelling' the web service call without calling Thread.Abort because that causes some strange behavior even if the only thing the thread is doing is calling this web service method.
How can i cancel or break from a synchronous method call (if it's even possible)?
Or should I try a different approach?
I have tried to use the AutoResetEvent and then calling Thread.Abort which is working fine in the below code sample, but when implementing this solution in the actual service I get some unexpected behavior probably because of what's going on in the external libraries I'm using.
AutoResetEvent and Thread.Abort:
class Program
{
static void Main(string[] args)
{
MainProgram p = new MainProgram();
p.Start();
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Q)
p.Stop();
}
}
class MainProgram
{
private Thread workerThread;
private Thread webServiceCallerThread;
private volatile bool doWork;
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.Start();
}
public void Stop()
{
doWork = false;
webServiceCallerThread.Abort();
}
private void DoWork()
{
try
{
while (doWork)
{
AutoResetEvent are = new AutoResetEvent(false);
WebServiceCaller caller = new WebServiceCaller(are);
webServiceCallerThread = new Thread(() => caller.TimeConsumingMethod());
webServiceCallerThread.Start();
// Wait for the WebServiceCaller.TimeConsumingMethod to finish
WaitHandle.WaitAll(new[] { are });
// If doWork has been signalled to stop
if (!doWork)
break;
// All good - continue
Console.WriteLine(caller.Result);
}
}
catch (Exception e)
{
Console.Write(e);
}
}
}
class WebServiceCaller
{
private AutoResetEvent ev;
private int result;
public int Result
{
get { return result; }
}
public WebServiceCaller(AutoResetEvent ev)
{
this.ev = ev;
}
public void TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(60000);
result = 1;
ev.Set();
}
catch (ThreadAbortException e)
{
ev.Set();
result = -1;
Console.WriteLine(e);
}
}
}
Can someone suggest a solution to this issue?
Try this
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.IsBackground = true;
workerThread.Start();
}
A thread is either a background thread or a foreground thread.
Background threads are identical to foreground threads, except that
background threads do not prevent a process from terminating. Once all
foreground threads belonging to a process have terminated, the common
language runtime ends the process. Any remaining background threads
are stopped and do not complete.
For more details see http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx
The solution is really this simple: Don't make calls that block for several minutes unless you want to block for several minutes. If there is no way to do a particular thing without blocking, potentially for several minutes, complain loudly to whoever wrote the code that imposes that painful requirement (or fix it yourself, if possible).
Once you've made the call, it's too late. You're committed. If the function you are calling doesn't provide a safe way to abort it, then there's no safe way.
As all you want to do is make one an asynchonrous web service call at a time and on each response make another call you can dispense with the worker thread and simply make an aynchronous call, register a callback and make another async call from the callback:
class Program
{
private static WebServiceCaller.TCMDelegate _wscDelegate;
private static readonly WebServiceCaller _wsCaller = new WebServiceCaller();
static void Main(string[] args)
{
_wscDelegate = _wsCaller.TimeConsumingMethod;
MakeWSCallAsync();
Console.WriteLine("Enter Q to quit");
while (Console.ReadLine().ToUpper().Trim()!="Q"){}
}
public static void MakeWSCallAsync()
{
_wscDelegate.BeginInvoke(OnWSCallComplete, null);
}
public static void OnWSCallComplete(IAsyncResult ar)
{
Console.WriteLine("Result {0}", _wscDelegate.EndInvoke(ar));
MakeWSCallAsync();
}
}
class WebServiceCaller
{
public delegate int TCMDelegate();
public int TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(1000);
return 1;
}
catch (ThreadAbortException e)
{
return -1;
}
}
}
No blocking (well, the console thread is blocking on ReadLine()) and no windows kernal mode sync objects (AutoResetEvent) which are expensive.

Ensuring that all callbacks were completed before sending a new request through a DuplexChannel using WCF

I am experiencing some issues when using a Callback in a WCF project.
First, the server invokes some function Foo on the client which then forwards the request to a Windows Forms GUI:
GUI CLASS
delegate void DoForward();
public void ForwardToGui() {
if (this.cmdSomeButton.InvokeRequired) {
DoForward d = new DoForward(ForwardToGui);
this.Invoke(d);
}
else {
Process(); // sets result variable in callback class as soon as done
}
}
}
CALLBACK CLASS
object _m = new object();
private int _result;
public int result {
get { return _result; }
set {
_result = value;
lock(_m) {
Monitor.PulseAll(_m);
}
}
}
[OperationContract]
public int Foo() {
result = 0;
Program.Gui.ForwardToGui();
lock(_m) {
Monitor.Wait(_m, 30000);
}
return result;
}
The problem now is that the user should be able to cancel the process, which doesn't work properly:
SERVER INTERFACE
[OperationContract]
void Cleanup();
GUI CLASS
private void Gui_FormClosed(object sender, EventArgs e) {
Program.callbackclass.nextAction = -1;
// so that the monitor pulses and Foo() returns
Program.server.Cleanup();
}
The problem with this is that Cleanup() hangs. However, when I close the form when Process() is not running, it works properly.
The source seems to be that the Cleanup() is called before the monitor pulses etc and therefore a new request is sent to the server before the last request from the server has not yet been responded.
How can I solve this problem? How can I ensure before calling Cleanup() that no Foo() is currently being executed?
The first warning I'm seeing is that you're calling Invoke instead of
BeginInvoke
Invoke waits until the action has been completed on the other thread before returning, which can result in a deadlock in some situations.

Categories