I've placed some very basic code below of what I'm trying to do. I have the 'DoSomethingAshnc' method that performs an Asynchronous operation. I would like the 'DoSomething' method to be a Synchronous method that doesn't take in the action parameter and returns an int.
public void DoSomething(Action<int> actionToPerformOnComplete)
{
DoSomethingAsync(delegate(int val)
{
actionToPerformOnComplete(val);
});
}
Is it even possible to have 'DoSomething' return an integer as if the method was happening synchronously?
You'd need to add something in the end of your sync method, to tell it to wait for the other call to finish. I'm assuming your async method will have an event on to tell the caller when it's finished.
If so then I'd suggest using something like a ManualResetEvent, waiting on it in your sync thread, and set it in the Finish event receiver for the async one.
Example:
public void DoSomething(Action<int> actionToPerformOnComplete)
{
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(delegate(int val)
{
try
{
actionToPerformOnComplete(val);
}
finally
{
mre.Set();
}
});
mre.WaitOne();
}
As others have mentioned, you need to wait for your async method to finish. To do that without passing that Action parameter to your method, use this code:
public int DoSomething()
{
int result;
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(val => {result = val; mre.Set(); });
mre.WaitOne();
return result;
}
This executes the async method, waits for it to finish and assigns the result to a local variable. This result is returned.
Yes. All you have to do is to put this line of code:
IAsyncResult asycn = ... // make a call to Async and get back IAsyncResult
while(!asycn.IsCompleted)
{
Thread.Sleep( ....);
}
UPDATE
Just as some asked, a correctly designed async operation will implement async pattern MSDN:
An asynchronous operation that uses
the IAsyncResult design pattern is
implemented as two methods named
BeginOperationName and
EndOperationName that begin and end
the asynchronous operation
OperationName respectively. For
example, the FileStream class provides
the BeginRead and EndRead methods to
asynchronously read bytes from a file.
These methods implement the
asynchronous version of the Read
method.
using System;
using System.Threading;
namespace qqq
{
class Program
{
public static void DoAsync(Action<int> whenDone)
{
new Thread(o => { Thread.Sleep(3000); whenDone(42); }).Start();
}
static public int Do()
{
var mre = new ManualResetEvent(false);
int retval = 0;
DoAsync(i => { retval = i; mre.Set(); });
if (mre.WaitOne())
return retval;
throw new ApplicationException("Unexpected error");
}
static void Main(string[] args)
{
Console.WriteLine(Do());
}
}
}
Related
I see the class Thread has 4 constructors:
public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
public Thread(ThreadStart start, int maxStackSize);
ParameterizedThreadStart and ThreadStart are delegate like this:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
What if I want to create thread start function that return int, for example?
I see that the constructor is good only if i want return void.
You can use the Task Parallel Library which allows you to have a return value. If you actually want a new thread to be allocated, you can use the right overload of Task.Factory.StartNew:
public int DoSomething() { return 42; }
public async Task FooAsync()
{
int value = await Task.Factory.StartNew(
() => DoSomething(), TaskCreationOptions.LongRunning);
}
If you don't actually need the new thread allocation, and can use a thread-pool thread, then using Task.Run is simpler and better:
public async Task FooAsync()
{
int value = await Task.Run(() => DoSomething());
}
Edit:
If for some odd reason you really want to use the Thread class, you can do this by closing over a variable and passing it to a delegate pass to Thread.Start and rely on the side-effect created once the thread starts running:
var x = 5;
var thread = new Thread(() =>
{
var x = DoSomething();
});
thread.Start();
thread.Join(); // This will synchronously block the thread.
Console.WriteLine(x);
Though I would definitely try to avoid this if you can use the TPL.
You can use:
public void StartThread()
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(this.DoWork);
Thread th = new Thread(pts);
int i =5;
th.Start(i);
}
public void DoWork(object data)
{
Console.WriteLine("I got data='{0}'", data);
}
or shorter
Thread th = new Thread(this.DoWork);
It is possible by creating the return value from the thread. Then you should take this variable by using a lambda expression. Assign to this variable a your "return" value from the worker thread and then it is necessary to wait till thread ends from the parent thread.
int value = 5; // a variable to store the return value
var thread = new Thread(() =>
{
value = 10; // Assign value to the return variable
});
thread.Start();
thread.Join();
Console.WriteLine(value); // use your variable to show in parent thread
I have a connection class which has several async methods such as SendText, SendImage etc.
The connection class has a Disconnect method, and when it is called I have to be careful not to start changing the inner state of the class before all async methods have completed execution.
I believe a good way to achieve this is to simply keep a running total of the number of operations in execution, and then when I want to Disconnect I can simply set Disconnecting = true and then wait for the count to reach 0
I'm thinking of something along the lines of this
class ReferenceCounter
{
void Increment();
void Decrement();
async Task WaitForCounterToReachZero();
}
Then when an async operation starts I could do
refCounter.Increment();
When it ends
refCounter.Decrement();
and inside the Disconnect method
disconnecting = true;
taskCancellationSource.Cancel();
await refCounter.WaitForCounterToReachZero();
Cleanup();
Are there any built in .NET classes like this?
Or more importantly for me, is there a better way of doing this?
If it was synchronous code it would be as simple as
lock (thisLock)
{
while (counter > 0)
Monitor.Wait(thisLock);
}
I just found the built in CountdownEvent class which does the same thing, but it has no async Wait method nor does it have any events, so I'd have to block.
Well, assuming you'll never increment again after you make it 0, you could do something like this:
public class Latch
{
private int count = 0;
private readonly TaskCompletionSource<object> tcs =
new TaskCompletionSource<object>();
public void Increment()
{
Interlocked.Increment(ref count);
}
public void Decrement()
{
if (Interlocked.Decrement(ref count) == 0)
{
tcs.TrySetValue(null);
}
}
public Task Task { get { return tcs.Task; } }
}
Then you can await someLatch.Task. Alternatively, you could make the latch itself awaitable:
public TaskAwaiter GetAwaiter()
{
return tcs.Task.GetAwaiter();
}
You should probably consider how you want to guard against the "count rises after getting down to 0" aspect thuogh - think about what you'd want it to do. (In the code above, once the TCS's value has been set, further awaits will complete immediately.)
WinForm:
I have a method called check_news in my MainApplication.
How can I create and run a Thread that will work on the method on background each time I call the method (by pushing a button, or in the start of the program)?
I know how to create a thread but how can I create new thread every time I call the function (new thread because the old one is dead)?
Should I create a new class and run the thread with the new class object and the method I need?
Where should I define the thread?
public void Example()
{
//call using a thread.
ThreadPool.QueueUserWorkItem(p => check_news("title", "news message"));
}
private void check_news(string news, string newsMessage)
{
}
You can just create a thread inside the method by writing new Thread(...).
The ... can be a method name, delegate instance, or anonymous method.
Each time this code executes, it will create a new Thread instance.
Note that it will be more efficient to use the ThreadPool instead.
I suppose the best way to achieve this is by adding it to the thread pool, it's easy and quick.
Example:
public static void Main(string[] args)
{
check_news();
}
private static void check_news()
{
ThreadPool.QueueUserWorkItem((obj) =>
{
// Fetch the news here
Thread.Sleep(1000); // Dummy
});
}
Or if you really want to deal with it yourself, this is something you could use:
public static void Main(string[] args)
{
check_news();
Console.ReadKey();
}
private static void check_news()
{
Thread t = new Thread(() =>
{
// Check news here
Thread.Sleep(1000); // Dummy
});
t.Priority = ThreadPriority.Lowest; // Priority of the thread
t.IsBackground = true; // Set it as background (allows you to stop the application while news is fetching
t.Name = "News checker"; // Make it recognizable
t.Start(); // And start it
}
But you should know that this takes a longer time to start, it doesn't reuse threads, and there's not a real advantage in it.
Or if you want more control you could use the async platform:
public static void Main(string[] args)
{
check_news(); // You can add an argument 'false' to stop it from executing async
Console.WriteLine("Done");
Console.ReadKey();
}
public delegate void Func();
public static void check_news(bool async = true)
{
Func checkNewsFunction = () =>
{
//Check news here
Thread.Sleep(1000);
};
if (async)
{
AsyncCallback callbackFunction = ar =>
{
// Executed when the news is received
};
checkNewsFunction.BeginInvoke(callbackFunction, null);
}
else
checkNewsFunction();
}
Note that the lambda expressions in all examples can just as well be replaced by regular functions. But I just use them right now, because it seems nicer as example.
Why does the delegate need to call the EndInvoke before the method fires? If i need to call the EndInvoke (which blocks the thread) then its not really an asynchronous call is it?
Here is the code im trying to run.
class Program
{
private delegate void GenerateXmlDelegate();
static void Main(string[] args)
{
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(null, null);
}
private static void GenerateMainXml()
{
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
The reason you need to call EndInvoke is to avoid memory leaks; .Net will store information about the function's result (or exception) until you call EndInvoke.
You can call EndInvoke in the completion handler that you give to BeginInvoke and retain the asyncronous nature.
EDIT:
For example:
class Program {
private delegate void GenerateXmlDelegate();
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(delegate {
try {
worker.EndInvoke();
} catch(...) { ... }
}, null);
}
private static void GenerateMainXml() {
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
If you want to fire an async call and forget about it, you can use the ThreadPool, like this:
ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); });
As SLaks said, EndInvoke insures against memory leaks.
BeginInvoke is still asynchronous; consider the following code:
static void Main() {
Func<double> slowCalculator = new Func<double>(PerformSlowCalculation);
IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null);
// lots of stuff to do while slowCalculator is doing its thing
Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation));
}
static double PerformSlowCalculation() {
double result;
// lots and lots of code
return result;
}
If this code were written without the BeginInvoke/EndInvoke calls, PerformSlowCalculation would have to finish before Main could do the rest of its "lots of stuff"; this way, the two can be happening at the same time.
Now, in your example using a GenerateXmlDelegate, you still need EndInvoke even though you're not returning anything. The way to do this is:
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null);
}
private static void GenerateXmlComplete(IAsyncResult result) {
AsyncResult realResult = result as AsyncResult;
GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate;
worker.EndInvoke();
}
I'm looking to implement a synchronous and asynchronous version of a method within a class library. Currently I've done this so that the Async method fires off a new Thread and does it's processing. To determine if the action has completed the user should poll a property to see if it has finished.
I'd like to improve it, I think it would be better to use some form of Async callback or result, but I'm not really sure how to go about implementing it, or, if indeed it is necessary. Can anyone offer any advice?
public static void Queue(Action action, Action done) {
ThreadPool.QueueUserWorkItem(_ =>
{
try {
action();
}
catch (ThreadAbortException) { /* dont report on this */ }
catch (Exception ex) {
Debug.Assert(false, "Async thread crashed! This must be fixed. " + ex.ToString());
}
// note: this will not be called if the thread is aborted
if (done != null) done();
});
}
Usage:
Queue( () => { Console.WriteLine("doing work"); },
() => { Console.WriteLine("work was done!"); } );
You can use a callback method instead of polling.
Check out my answer on AsyncCallback
Edited:
Example of FileCopy using own async delegates with callback:
public class AsyncFileCopier
{
public delegate void FileCopyDelegate(string sourceFile, string destFile);
public static void AsynFileCopy(string sourceFile, string destFile)
{
FileCopyDelegate del = new FileCopyDelegate(FileCopy);
IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
}
public static void FileCopy(string sourceFile, string destFile)
{
// Code to copy the file
}
public static void CallBackAfterFileCopied(IAsyncResult result)
{
// Code to be run after file copy is done
}
}
You can call it as:
AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");
Asynchronous Delegates could be another option.
Read about Asynchronous Programming Using Delegates on MSDN