From what I can tell, there is no built-in (or framework extension) support for ConnectAsync/AcceptAsync/SendAsync/ReceiveAsync, etc.. How would I write my own wrapper that would be supported by the async-await mechanism. For example, my current code which handles a ReceiveAsync both inline and on the callback (which is specified in the SocketAsyncEventArgs):
private void PostReceive(SocketAsyncEventArgs e)
{
e.SetBuffer(ReceiveBuffer.DataBuffer, ReceiveBuffer.Count, ReceiveBuffer.Remaining);
e.Completed += Receive_Completed;
// if ReceiveAsync returns false, then completion happened inline
if (m_RemoteSocket.ReceiveAsync(e) == false)
{
Receive_Completed(this, e);
}
}
.
private void Receive_Completed(object sender, SocketAsyncEventArgs e)
{
e.Completed -= Receive_Completed;
if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
{
if (e.BytesTransferred > 0)
{
OnDataReceived(e);
}
Disconnect(e);
return;
}
OnDataReceived(e);
//
// we do not push the SocketAsyncEventArgs back onto the pool, instead
// we reuse it in the next receive call
//
PostReceive(e);
}
The trick is to use TaskCompletionSource to handle this scenario.
I blogged about this. For details, see Preparing Existing code For Await.
You can also write a custom awaitable, which I like better in this situation. This is a technique by Stephen Toub from Microsoft. You can read more about this technique here.
http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
Here is the custom awaitable:
public sealed class SocketAwaitable : INotifyCompletion
{
private readonly static Action SENTINEL = () => { };
internal bool m_wasCompleted;
internal Action m_continuation;
internal SocketAsyncEventArgs m_eventArgs;
public SocketAwaitable(SocketAsyncEventArgs eventArgs)
{
if (eventArgs == null) throw new ArgumentNullException("eventArgs");
m_eventArgs = eventArgs;
eventArgs.Completed += delegate
{
var prev = m_continuation ?? Interlocked.CompareExchange(
ref m_continuation, SENTINEL, null);
if (prev != null) prev();
};
}
internal void Reset()
{
m_wasCompleted = false;
m_continuation = null;
}
public SocketAwaitable GetAwaiter() { return this; }
public bool IsCompleted { get { return m_wasCompleted; } }
public void OnCompleted(Action continuation)
{
if (m_continuation == SENTINEL ||
Interlocked.CompareExchange(
ref m_continuation, continuation, null) == SENTINEL)
{
Task.Run(continuation);
}
}
public void GetResult()
{
if (m_eventArgs.SocketError != SocketError.Success)
throw new SocketException((int)m_eventArgs.SocketError);
}
}
Some extension methods to add to the socket class and make it convenient:
public static class SocketExtensions
{
public static SocketAwaitable ReceiveAsync(this Socket socket,
SocketAwaitable awaitable)
{
awaitable.Reset();
if (!socket.ReceiveAsync(awaitable.m_eventArgs))
awaitable.m_wasCompleted = true;
return awaitable;
}
public static SocketAwaitable SendAsync(this Socket socket,
SocketAwaitable awaitable)
{
awaitable.Reset();
if (!socket.SendAsync(awaitable.m_eventArgs))
awaitable.m_wasCompleted = true;
return awaitable;
}
// ...
}
In use:
static async Task ReadAsync(Socket s)
{
// Reusable SocketAsyncEventArgs and awaitable wrapper
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[0x1000], 0, 0x1000);
var awaitable = new SocketAwaitable(args);
// Do processing, continually receiving from the socket
while (true)
{
await s.ReceiveAsync(awaitable);
int bytesRead = args.BytesTransferred;
if (bytesRead <= 0) break;
Console.WriteLine(bytesRead);
}
}
For socket stuff there is a wrapper in .NET 4.5. If you are on .NET 4 I'd recommend to use the APM and not the event-based asynchronous pattern. It converts to Task's far more easily.
Related
I’ve got a .NET application that needs to call a COM object (it always has to be called from the same thread). As I have multiple threads in the application, I need to invoke an action on another thread.
The application does not have a (standard) message loop and I don’t really like the idea to add WPF / WinForms just to have a Dispatcher.
What would be a safe and effective way to implement a custom "message loop" / queue that allows invoking an Action / Func (with return type) on another thread?
It would also be nice to have a cross-platform solution for this problem.
Based on the information of #theodor-zoulias, I came up with this solution.
Disclaimer: Might be that this is actually a very bad design!
public sealed class DispatcherLoop : IDisposable
{
#region Instance
private DispatcherLoop() { }
static Dictionary<int, DispatcherLoop> dispatcherLoops = new();
public static DispatcherLoop Current
{
get
{
int threadId = Thread.CurrentThread.ManagedThreadId;
if (dispatcherLoops.ContainsKey(threadId))
return dispatcherLoops[threadId];
DispatcherLoop dispatcherLoop = new()
{
ThreadId = Thread.CurrentThread.ManagedThreadId
};
dispatcherLoops.Add(threadId, dispatcherLoop);
return dispatcherLoop;
}
}
#endregion
bool isDisposed = false;
public void Dispose()
{
if (isDisposed)
throw new ObjectDisposedException(null);
_queue.CompleteAdding();
_queue.Dispose();
dispatcherLoops.Remove(ThreadId);
isDisposed = true;
}
public int ThreadId { get; private set; } = -1;
public bool IsRunning { get; private set; } = false;
BlockingCollection<Task> _queue = new();
public void Run()
{
if (isDisposed)
throw new ObjectDisposedException(null);
if (ThreadId != Thread.CurrentThread.ManagedThreadId)
throw new InvalidOperationException($"The {nameof(DispatcherLoop)} has been created for a different thread!");
if (IsRunning)
throw new InvalidOperationException("Already running!");
IsRunning = true;
try
{
// ToDo: `RunSynchronously` is not guaranteed to be executed on this thread (see comments below)!
foreach (var task in _queue.GetConsumingEnumerable())
task?.RunSynchronously();
}
catch (ObjectDisposedException) { }
IsRunning = false;
}
public void BeginInvoke(Task task)
{
if (isDisposed)
throw new ObjectDisposedException(null);
if (!IsRunning)
throw new InvalidOperationException("Not running!");
if (ThreadId == Thread.CurrentThread.ManagedThreadId)
task?.RunSynchronously();
else
_queue.Add(task);
}
public void Invoke(Action action)
{
if (isDisposed)
throw new ObjectDisposedException(null);
Task task = new(action);
BeginInvoke(task);
task.GetAwaiter().GetResult();
}
public T Invoke<T>(Func<T> action)
{
if (isDisposed)
throw new ObjectDisposedException(null);
Task<T> task = new(action);
BeginInvoke(task);
return task.GetAwaiter().GetResult();
}
}
You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then you can do this:
var els = new EventLoopScheduler();
Then you can do things like this:
els.Schedule(() => Console.WriteLine("Hello, World!"));
The EventLoopScheduler spins up its own thread and you can ask it to schedule any work on it you like - it'll always be that thread.
When you're finished with the scheduler, just call els.Dispose() to shut down it down cleanly.
There are also plenty of overloads for scheduling code in the future. It's a very powerful class.
I want to reduce multiple events into a single delayed action. After some trigger occurs I expect some more similar triggers to come, but I prefer not to repeat the resulting delayed action. The action waits, to give a chance of completion to the burst.
The question: How can I do it in an elegant reusable way?
Till now I used a property to flag the event and trigger a delayed action like below:
public void SomeMethod()
{
SomeFlag = true; //this will intentionally return to the caller before completing the resulting buffered actions.
}
private bool someFlag;
public bool SomeFlag
{
get { return someFlag; }
set
{
if (someFlag != value)
{
someFlag = value;
if (value)
SomeDelayedMethod(5000);
}
}
}
public async void SomeDelayedMethod(int delay)
{
//some bufferred work.
await Task.Delay(delay);
SomeFlag = false;
}
below is a shorter way, but still not generic or reusable... I want something concise that packages the actions and the flag, and keeps the functionality (returning to the caller before execution is complete (like today)). I also need to be able to pass an object reference to this action)
public void SerializeAccountsToConfig()
{
if (!alreadyFlagged)
{
alreadyFlagged = true;
SerializeDelayed(5000, Serialize);
}
}
public async void SerializeDelayed(int delay, Action whatToDo)
{
await Task.Delay(delay);
whatToDo();
}
private bool alreadyFlagged;
private void Serialize()
{
//some buferred work.
//string json = JsonConvert.SerializeObject(Accounts, Formatting.Indented);
//Settings1.Default.Accounts = json;
//Settings1.Default.Save();
alreadyFlagged = false;
}
Here's a thread-safe and reusable solution.
You can create an instance of DelayedSingleAction, and in the constructor you pass the action that you want to have performed. I believe this is thread safe, though there is a tiny risk that it will restart the timer just before commencing the action, but I think that risk would exist no matter what the solution is.
public class DelayedSingleAction
{
private readonly Action _action;
private readonly long _millisecondsDelay;
private long _syncValue = 1;
public DelayedSingleAction(Action action, long millisecondsDelay)
{
_action = action;
_millisecondsDelay = millisecondsDelay;
}
private Task _waitingTask = null;
private void DoActionAndClearTask(Task _)
{
Interlocked.Exchange(ref _syncValue, 1);
_action();
}
public void PerformAction()
{
if (Interlocked.Exchange(ref _syncValue, 0) == 1)
{
_waitingTask = Task.Delay(TimeSpan.FromMilliseconds(_millisecondsDelay))
.ContinueWith(DoActionAndClearTask);
}
}
public Task Complete()
{
return _waitingTask ?? Task.FromResult(0);
}
}
See this dotnetfiddle for an example which invokes one action continuously from multiple threads.
https://dotnetfiddle.net/el14wZ
Since you're interested in RX here simple console app sample:
static void Main(string[] args)
{
// event source
var burstEvents = Observable.Interval(TimeSpan.FromMilliseconds(50));
var subscription = burstEvents
.Buffer(TimeSpan.FromSeconds(3)) // collect events 3 seconds
//.Buffer(50) // or collect 50 events
.Subscribe(events =>
{
//Console.WriteLine(events.First()); // take only first event
// or process event collection
foreach (var e in events)
Console.Write(e + " ");
Console.WriteLine();
});
Console.ReadLine();
return;
}
Based on the solution proposed by Andrew, here is a more generic solution.
Declaration and instance creation of the delayed action:
public DelayedSingleAction<Account> SendMailD;
Create the instance inside a function or in the constructor (this can be a collection of such actions each working on a different object):
SendMailD = new DelayedSingleAction<Account>(SendMail, AccountRef, 5000);
repeatedly call this action
SendMailD.PerformAction();
Send mail is the action you will "burst control". Its signature matches :
public int SendMail(Account A)
{}
Here is the updated class
public class DelayedSingleAction<T>
{
private readonly Func<T, int> actionOnObj;
private T tInstance;
private readonly long millisecondsDelay;
private long _syncValue = 1;
public DelayedSingleAction(Func<T, int> ActionOnObj, T TInstance, long MillisecondsDelay)
{
actionOnObj = ActionOnObj;
tInstance = TInstance;
millisecondsDelay = MillisecondsDelay;
}
private Task _waitingTask = null;
private void DoActionAndClearTask(Task _)
{
Console.WriteLine(string.Format("{0:h:mm:ss.fff} DelayedSingleAction Resetting SyncObject: Thread {1} for {2}", DateTime.Now, System.Threading.Thread.CurrentThread.ManagedThreadId, tInstance));
Interlocked.Exchange(ref _syncValue, 1);
actionOnObj(tInstance);
}
public void PerformAction()
{
if (Interlocked.Exchange(ref _syncValue, 0) == 1)
{
Console.WriteLine(string.Format("{0:h:mm:ss.fff} DelayedSingleAction Starting the timer: Thread {1} for {2}", DateTime.Now, System.Threading.Thread.CurrentThread.ManagedThreadId, tInstance));
_waitingTask = Task.Delay(TimeSpan.FromMilliseconds(millisecondsDelay)).ContinueWith(DoActionAndClearTask);
}
}
public Task Complete()
{
return _waitingTask ?? Task.FromResult(0);
}
}
I have some logging code that was written to intercept method calls using ContextBoundObject s and a ContextAttribute. The code is based on a Code Project sample.
This all worked fine until we started using this library with code that leverages async and await. Now we get remoting errors when running the code. Here is a simple example that reproduces the issue:
public class OhMyAttribute : ContextAttribute
{
public OhMyAttribute() : base("OhMy")
{
}
}
[OhMy]
public class Class1 : ContextBoundObject
{
private string one = "1";
public async Task Method1()
{
Console.WriteLine(one);
await Task.Delay(50);
Console.WriteLine(one);
}
}
When we invoke Method1 we get the following RemotingException on the second Console.WriteLine:
Remoting cannot find field 'one' on type 'WindowsFormsApplication1.Class1'.
Is there any way to get around this problem using built in C# methods or do we have to look at an alternative solution like PostSharp?
Short answer: Remoting calls do not work on private fields. The async/await rewriting causes an attempt to make a remoting call on a private field.
The issue can be reproduced without async/await. And demonstrating it this way is helpful in understanding what is going on in the async/await case:
[OhMy]
public class Class2 : ContextBoundObject
{
private string one = "1";
public void Method1()
{
var nc = new NestedClass(this);
}
public class NestedClass
{
public NestedClass(Class2 c2)
{
Console.WriteLine(c2.one); // Note: nested classes are allowed access to outer classes privates
}
}
}
static void Main(string[] args)
{
var c2 = new Class2();
// This call causes no problems:
c2.Method1();
// This, however, causes the issue.
var nc = new Class2.NestedClass(c2);
}
Let's walk through what happens line by line:
In Main, we start out in Context0
Since Class2 is a ContextBoundObject and since the OhMyAttribute considers the current context unacceptable, an instance of Class2 is created in Context1 (I'll call this c2_real, and what is returned and stored in c2 is a remoting proxy to c2_real.
When c2.Method1() is called, it is called on the remote proxy. Since we are in Context0, the remote proxy realizes it is not in the correct context so it switches to Context1, and the code within Method1 is executed.
3.a Within Method1 we call the NestedClass constructor which uses c2.one. In this case, we are already in Context1, so the c2.one requires no context switches and so we are using the c2_real object directly.
Now, the problematic case:
We create a new NestedClass passing in the remote proxy c2. No context switches occur here because NestedClass is not a ContextBoundObject.
Within the NestedClass ctor, it access c2.one. The remote proxy notices that we are still in Context0, and so it attempts to remote this call to Context1. This fails because c2.one is a private field. You'll see in Object.GetFieldInfo it is only looking for Public fields:
private FieldInfo GetFieldInfo(String typeName, String fieldName)
{
// ...
FieldInfo fldInfo = t.GetField(fieldName, BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.IgnoreCase);
if(null == fldInfo)
{
#if FEATURE_REMOTING
throw new RemotingException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_BadField"),
fieldName, typeName));
// ...
}
return fldInfo;
}
So, How does async/await end up causing this same issue?
The async/await causes your Class1 to get rewritten such that it uses a nested class with a state machine (used ILSpy to generate):
public class Class1 : ContextBoundObject
{
// ...
private struct <Method1>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
public Class1 <>4__this;
private TaskAwaiter <>u__$awaiter1;
private object <>t__stack;
void IAsyncStateMachine.MoveNext()
{
try
{
int num = this.<>1__state;
if (num != -3)
{
TaskAwaiter taskAwaiter;
if (num != 0)
{
Console.WriteLine(this.<>4__this.one);
taskAwaiter = Task.Delay(50).GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
this.<>1__state = 0;
this.<>u__$awaiter1 = taskAwaiter;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Class1.<Method1>d__0>(ref taskAwaiter, ref this);
return;
}
}
else
{
taskAwaiter = this.<>u__$awaiter1;
this.<>u__$awaiter1 = default(TaskAwaiter);
this.<>1__state = -1;
}
taskAwaiter.GetResult();
taskAwaiter = default(TaskAwaiter);
Console.WriteLine(this.<>4__this.one);
}
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<>1__state = -2;
this.<>t__builder.SetResult();
}
// ...
}
private string one = "1";
public Task Method1()
{
Class1.<Method1>d__0 <Method1>d__;
<Method1>d__.<>4__this = this;
<Method1>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<Method1>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <Method1>d__.<>t__builder;
<>t__builder.Start<Class1.<Method1>d__0>(ref <Method1>d__);
return <Method1>d__.<>t__builder.Task;
}
}
The important thing to notice is that
It's created a nested structure which has access to the privates of Class1
The this variable is lifted and stored in the nested class.
So, what happens here is that
On the initial call to c1.Method1() the remoting proxy notices we are in Context0, and that it needs to switch to Context1.
Eventually, MoveNext is called, and c1.one is called. Since we are already in Context1, no context switch is necessary (so the issue doesn't occur).
Later, since a continuation was registered, a call to MoveNext will occur again to execute the rest of the code after the await. However, this call to MoveNext will not occur inside a call to one of Class1's methods. Thus, when the code c1.one is executed this time, we will be in Context0. The remoting proxy notices we are in Context0, and attempts a context switch. This causes the same failure as above since c1.one is a private field.
Workaround:
I'm not sure of a general workaround, but for this specific case you can work around the issue by not using the this reference in the method. I.e.:
public async Task Method1()
{
var temp = one;
Console.WriteLine(temp);
await Task.Delay(50);
Console.WriteLine(temp);
}
Or switch to using a private property instead of a field.
Here is a more general workaround.
It has the following deficiencies:
It does not support changing the SynchronizationContext within the ContextBoundObject. It will throw in that case.
It does not support the case of using await when SynchronizationContext.Current is null and the TaskScheduler.Current is not the TaskScheduler.Default. In this scenario, normally await would capture the TaskScheduler and use that to post the remainder of the work, but since this solution sets the SynchronizationContext the TaskScheduler would not be captured. Thus, when this situation is detected, it will throw.
It does not support using .ConfigureAwait(false) since that will cause the SynchronizationContext to not be captured. Unfortunately, I could not detect this case. However, if the user does want to get .ConfigureAwait(false) like behavior for the underlying pass-through SynchronizationContext, they can use a custom awaiter (see https://stackoverflow.com/a/22417031/495262).
One interesting thing here is that I've attempted to create a "pass through" SynchronizationContext. That is, I didn't want to overwrite any existing SynchronizationContext, but rather retain its behavior and layer on top of it the behavior of doing the work in the proper context. Any comments on a better approach are welcome.
using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var c1 = new Class1();
var t = c1.Method1();
Func<Task> f = c1.Method1;
f.BeginInvoke(null, null);
Console.ReadKey();
}
}
[MyContext]
public class Class1 : ContextBoundObject
{
private string one = "1";
public async Task Method1()
{
Console.WriteLine(one);
await Task.Delay(50);
Console.WriteLine(one);
}
}
sealed class MyContextAttribute : ContextAttribute
{
public MyContextAttribute()
: base("My")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
if (ctorMsg == null)
throw new ArgumentNullException("ctorMsg");
ctorMsg.ContextProperties.Add(new ContributeInstallContextSynchronizationContextMessageSink());
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
return false;
}
}
sealed class ContributeInstallContextSynchronizationContextMessageSink : IContextProperty, IContributeServerContextSink
{
public ContributeInstallContextSynchronizationContextMessageSink()
{
}
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new InstallContextSynchronizationContextMessageSink(nextSink);
}
public string Name { get { return "ContributeInstallContextSynchronizationContextMessageSink"; } }
public bool IsNewContextOK(Context ctx)
{
return true;
}
public void Freeze(Context ctx)
{
}
}
sealed class InstallContextSynchronizationContextMessageSink : IMessageSink
{
readonly IMessageSink m_NextSink;
public InstallContextSynchronizationContextMessageSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
}
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
var contextSyncContext = new ContextSynchronizationContext(SynchronizationContext.Current);
var syncContextReplacer = new SynchronizationContextReplacer(contextSyncContext);
DelegateMessageSink.SyncProcessMessageDelegate replySyncDelegate = (n, m) => SyncProcessMessageDelegateForAsyncReply(n, m, syncContextReplacer);
var newReplySink = new DelegateMessageSink(replySink, replySyncDelegate, null);
return m_NextSink.AsyncProcessMessage(msg, newReplySink);
}
public IMessage SyncProcessMessage(IMessage msg)
{
var contextSyncContext = new ContextSynchronizationContext(SynchronizationContext.Current);
using (new SynchronizationContextReplacer(contextSyncContext))
{
var ret = m_NextSink.SyncProcessMessage(msg);
return ret;
}
}
private IMessage SyncProcessMessageDelegateForAsyncReply(IMessageSink nextSink, IMessage msg, SynchronizationContextReplacer syncContextReplacer)
{
syncContextReplacer.Dispose();
return nextSink.SyncProcessMessage(msg);
}
private void PreChecks()
{
if (SynchronizationContext.Current != null)
return;
if (TaskScheduler.Current != TaskScheduler.Default)
throw new InvalidOperationException("InstallContextSynchronizationContextMessageSink does not support calling methods with SynchronizationContext.Current as null while Taskscheduler.Current is not TaskScheduler.Default");
}
}
sealed class SynchronizationContextReplacer : IDisposable
{
SynchronizationContext m_original;
SynchronizationContext m_new;
public SynchronizationContextReplacer(SynchronizationContext syncContext)
{
m_original = SynchronizationContext.Current;
m_new = syncContext;
SynchronizationContext.SetSynchronizationContext(m_new);
}
public void Dispose()
{
// We don't expect the SynchronizationContext to be changed during the lifetime of the SynchronizationContextReplacer
if (SynchronizationContext.Current != m_new)
throw new InvalidOperationException("SynchronizationContext was changed unexpectedly.");
SynchronizationContext.SetSynchronizationContext(m_original);
}
}
sealed class ContextSynchronizationContext : PassThroughSynchronizationConext
{
readonly Context m_context;
private ContextSynchronizationContext(SynchronizationContext passThroughSyncContext, Context ctx)
: base(passThroughSyncContext)
{
if (ctx == null)
throw new ArgumentNullException("ctx");
m_context = ctx;
}
public ContextSynchronizationContext(SynchronizationContext passThroughSyncContext)
: this(passThroughSyncContext, Thread.CurrentContext)
{
}
protected override SynchronizationContext CreateCopy(SynchronizationContext copiedPassThroughSyncContext)
{
return new ContextSynchronizationContext(copiedPassThroughSyncContext, m_context);
}
protected override void CreateSendOrPostCallback(SendOrPostCallback d, object state)
{
CrossContextDelegate ccd = () => d(state);
m_context.DoCallBack(ccd);
}
}
abstract class PassThroughSynchronizationConext : SynchronizationContext
{
readonly SynchronizationContext m_passThroughSyncContext;
protected PassThroughSynchronizationConext(SynchronizationContext passThroughSyncContext)
: base()
{
m_passThroughSyncContext = passThroughSyncContext;
}
protected abstract void CreateSendOrPostCallback(SendOrPostCallback d, object state);
protected abstract SynchronizationContext CreateCopy(SynchronizationContext copiedPassThroughSyncContext);
public sealed override void Post(SendOrPostCallback d, object state)
{
var d2 = CreateSendOrPostCallback(d);
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.Post(d2, state);
else
base.Post(d2, state);
}
public sealed override void Send(SendOrPostCallback d, object state)
{
var d2 = CreateSendOrPostCallback(d);
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.Send(d2, state);
else
base.Send(d2, state);
}
public sealed override SynchronizationContext CreateCopy()
{
var copiedSyncCtx = m_passThroughSyncContext != null ? m_passThroughSyncContext.CreateCopy() : null;
return CreateCopy(copiedSyncCtx);
}
public sealed override void OperationCompleted()
{
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.OperationCompleted();
else
base.OperationCompleted();
}
public sealed override void OperationStarted()
{
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.OperationStarted();
else
base.OperationStarted();
}
public sealed override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return m_passThroughSyncContext != null ?
m_passThroughSyncContext.Wait(waitHandles, waitAll, millisecondsTimeout) :
base.Wait(waitHandles, waitAll, millisecondsTimeout);
}
private SendOrPostCallback CreateSendOrPostCallback(SendOrPostCallback d)
{
SendOrPostCallback sopc = s => CreateSendOrPostCallback(d, s);
return sopc;
}
}
sealed class DelegateMessageSink : IMessageSink
{
public delegate IMessage SyncProcessMessageDelegate(IMessageSink nextSink, IMessage msg);
public delegate IMessageCtrl AsyncProcessMessageDelegate(IMessageSink nextSink, IMessage msg, IMessageSink replySink);
readonly IMessageSink m_NextSink;
readonly SyncProcessMessageDelegate m_syncProcessMessageDelegate;
readonly AsyncProcessMessageDelegate m_asyncProcessMessageDelegate;
public DelegateMessageSink(IMessageSink nextSink, SyncProcessMessageDelegate syncProcessMessageDelegate, AsyncProcessMessageDelegate asyncProcessMessageDelegate)
{
m_NextSink = nextSink;
m_syncProcessMessageDelegate = syncProcessMessageDelegate;
m_asyncProcessMessageDelegate = asyncProcessMessageDelegate;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return (m_asyncProcessMessageDelegate != null) ?
m_asyncProcessMessageDelegate(m_NextSink, msg, replySink) :
m_NextSink.AsyncProcessMessage(msg, replySink);
}
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessage SyncProcessMessage(IMessage msg)
{
return (m_syncProcessMessageDelegate != null) ?
m_syncProcessMessageDelegate(m_NextSink, msg) :
m_NextSink.SyncProcessMessage(msg);
}
}
}
I have an application that opens a socket and sends information over it. This functionality is encapsulated in a class.
I thought that it could be easy to work in parallel if I run this feature with Parallel.ForEach. In this way, each task would open/close a socket and send over it (to the same ip/port). This solution doesn't works.
Second way, I am implementing the socket operation in asynchronous way, and the behavior is that the server receives all data from first task and later the rest of data from other task. From the server side, there's no parallel behavior.
I am searching and reading information about this but I can't solve this problem.
Any ideas? Do you have a complete sample of using socket with Parallel library? Or any complete sample of using sockets in multithreading environment?
Complementary information:
I have a LINQ expression that returns a list of files. This list is processed as this:
Parallel.ForEach(AllFiles, new ParallelOptions { MaxDegreeOfParallelism = _maxDegreeOfParallelism }, currentFile =>
{
ProcessFiles(currentFile);
});
...
ProcessFiles sumarized:
void ProcessFile (string currentFile)
{
MyTcpClient client = null;
try
{
var AllLinesInFiles = // LINQ Expression that returns a list of strings
int port = 23000;
client = new MyTcpServer(ip, port);
foreach (string data in AllLinesInFiles)
{
if (data.Length > 0)
{
if (!client.IsOk)
{
client.Connect(false);
if (!client.IsOk)
break;
}
client.SendMessage(tmpLine2);
}
}
}
catch (Exception ex)
{
...
}
finally
{
if ((client != null) && (client.IsOk))
client.Close();
}
}
MyTcpClient, synchronous version is:
public class MyTcpClient : IDisposable
{
private static object objLock = new object();
public int Port = ...
public IPAddress IPAddress = ...
private string _Host;
private TcpClient _client = null;
private Stream _stream = null;
static MyTcpClient()
{
}
public MyTcpClient(string PassedIPAddress, Int32 PassedPort)
{
try
{
this.IPAddress = PassedIPAddress;
this.Port = PassedPort;
}
catch (Exception ex)
{
...
}
}
public TcpClient TcpClient
{
get { return _client; }
set { _client = value; }
}
public X509Certificate Certificate
{
get { return _certificate; }
set { _certificate = value; }
}
public bool IsOk
{
get
{
return ((_client != null) && (_client.Connected));
}
}
public void Connect(bool isSecure)
{
if (IsOk == false)
{
_client = new TcpClient(this.IPAddress.ToString(), this.Port);
_stream = null;
try
{
NetworkStream networkStream = _client.GetStream();
_stream = (NetworkStream)networkStream;
}
catch (AuthenticationException ex)
{
...
}
catch (Exception ex)
{
...
}
finally
{
}
}
}
public void SendMessage(string message)
{
if (_client != null && IsOk)
{
byte[] dgram = EncodingHelper.GetEncoding().GetBytes(message);
lock (MyTcpClient.objLock)
{
_stream.Write(dgram, 0, dgram.Length);
}
}
}
public void SendMessage(byte[] dgram)
{
if (_client != null && IsOk)
{
lock (MyTcpClient.objLock)
{
_stream.Write(dgram, 0, dgram.Length);
}
}
}
public void Close()
{
this.Dispose();
}
public void Dispose()
{
if (_stream != null)
{
_stream.Close();
}
if (_client != null)
{
_client.Close();
}
}
}
And for the Asynchronous version I have used the example here http://msdn.microsoft.com/en-us/library/bew39x2a.aspx
When I use asynchronous socket client, I update ProcessFile method but, the idea is open/close the socket in this method.
I'm working on a little technical framework for CF.NET and my question is, how should I code the asynchronous part? Read many things on MSDN but isn't clear for me.
So, here is the code :
public class A
{
public IAsyncResult BeginExecute(AsyncCallback callback)
{
// What should I put here ?
}
public void EndExecute()
{
// What should I put here ?
}
public void Execute()
{
Thread.Sleep(1000 * 10);
}
}
If someone can help me...
Thanks !
You could use a delegate:
public class A
{
public void Execute()
{
Thread.Sleep(1000 * 3);
}
}
class Program
{
static void Main()
{
var a = new A();
Action del = (() => a.Execute());
var result = del.BeginInvoke(state =>
{
((Action)state.AsyncState).EndInvoke(state);
Console.WriteLine("finished");
}, del);
Console.ReadLine();
}
}
UPDATE:
As requested in the comments section here's a sample implementation:
public class A
{
private Action _delegate;
private AutoResetEvent _asyncActiveEvent;
public IAsyncResult BeginExecute(AsyncCallback callback, object state)
{
_delegate = () => Execute();
if (_asyncActiveEvent == null)
{
bool flag = false;
try
{
Monitor.Enter(this, ref flag);
if (_asyncActiveEvent == null)
{
_asyncActiveEvent = new AutoResetEvent(true);
}
}
finally
{
if (flag)
{
Monitor.Exit(this);
}
}
}
_asyncActiveEvent.WaitOne();
return _delegate.BeginInvoke(callback, state);
}
public void EndExecute(IAsyncResult result)
{
try
{
_delegate.EndInvoke(result);
}
finally
{
_delegate = null;
_asyncActiveEvent.Set();
}
}
private void Execute()
{
Thread.Sleep(1000 * 3);
}
}
class Program
{
static void Main()
{
A a = new A();
a.BeginExecute(state =>
{
Console.WriteLine("finished");
((A)state.AsyncState).EndExecute(state);
}, a);
Console.ReadLine();
}
}
You don't need to do anything special, cause the caller should call you method async,
He define a new delegate pointing to you method, and use the .net to call your method asynchronously.
On BeginExecute you have to start the asynchronous operation (possibly start execute in a separate thread) and return as quick as possible. Execute has to call the AsyncCallback at the end of all operations so that who use the async operation gets aware and get the result. EndExecute has to stop a previously started async operation (possibly interrupting the thread launched by BeginExecute).
Without more details this is the best I can do.
If you want to run piece of code asynchronously, you should use BackgroundWorker. Unless of course, the code you are calling doesn't support asynchronous operation natively. Just like Read/Write methods or service calls.
If you want to notify, that the asynchronous operation has finished, use delegate or event callback.