I am trying to make a function that when called returns back information to the caller that is on a server. What I want in this function, is that it creates a thread that issues the command to the server, and then suspends itself until the server responds back with the answer.
public AccountState GetAccount(string key)
{
AccountState state = null;
Thread t = new Thread(() =>
{
_connection.SomeCommandSentToServer(key);
accountRequests.TryAdd(key, (Thread.CurrentThread, null));
//Suspend current thread until ServerReponseHere is called
Thread.CurrentThread.Suspend();
//We have been resumed, value should be in accountRequests now
accountRequests.TryRemove(key, out var item);
state = item.AccountState;
});
t.Start();
return state;
}
public ConcurrentDictionary<string, (Thread Thread, AccountState AccountState)> accountRequests = new ConcurrentDictionary<string, (Thread Thread, AccountState AccountState)>();
///Once server is done with processed command, call to this function made
public void ServerReponseHere(string key, AccountState state)
{
accountRequests.TryGetValue(username, out var item);
accountRequests.TryUpdate(username, (item.Thread, new AccountState()), item);
item.Thread.Resume();
}
My Idea then is that in a different function, when server responds back, it calls the ResumeThread function shown above.
C# says that Suspend / Resume are deprecated functions however, -- what is a better way to do this?
UPDATE
Clarification about "SomeCommandSentToServer" -- This just sends a command to the server via TCP sockets.
In that call, all that is really happening is a transmission to the server. I'm using a library that uses WinSock2.h call of "Send()" -- Yes I know it is a deprecated library... but the library I'm using requires it.
I have a separate thread that polls input from the server. So I have no way to "await" on this SomeCommandSentToServer -- I would need to await on some sort of call back function (aka the resume function I was mentioning) -- to make this work.
I am unsure how to do that
With all the information available from the question, here is what you should aim for when using the async / await pattern:
public async Task<AccountState> GetAccountAsync(string key)
{
// The method SomeCommandSentToServerAsync must be changed to support async.
AccountState state = await _connection.SomeCommandSentToServerAsync(key);
return state;
}
It is highly unlikely that you need anything else. By that, I mean you will not have to manipulate threads directly, put them in a concurrent dictionary and manually suspend or resume them because it looks horrible from a maintenance perspective ;)
.NET will take care of the threading part, meaning the magic of the async infrastructure will most likely release the current thread (assuming a call is actually made to the server) until the server returns a response.
Then the infrastructure will either use the existing synchronization context -if you are on a UI thread for instance- or grab a thread from the thread pool -if not- to run the rest of the method.
You could even reduce the size of the method a bit more by simply returning a Task with a result of type AccountState:
public Task<AccountState> GetAccountAsync(string key)
{
// The method SomeCommandSentToServerAsync must be changed to support async.
return _connection.SomeCommandSentToServerAsync(key);
}
In both example, you will haver to make the callers async as well:
public async Task TheCallerAsync()
{
// Grab the key from somewhere.
string key = ...;
var accountState = await <inst>.GetAccountAsync(key);
// Do something with the state.
...
}
Turning a legacy method into an async method
Now, regarding the legacy SomeCommandSentToServer method. There is a way to await that legacy method. Yes, you can turn that method into an asynchronous method that can be used with the async / await.
Of course, I do not have all the details of your implementation but I hope you will get the idea of what needs to be done. The magical class to do that is called TaskCompletionSource.
What it allows you to do is to give you access to a Task. You create the instance of that TaskCompletionSource class, you keep it somewhere, you send the command and immediately return the Task property of that new instance.
Once you get the result from your polling thread, you grab the instance of TaskCompletionSource, get the AccountState and call SetResult with the account state. This will mark the task as completed and do the resume part you were asking for :)
Here is the idea:
public Task<AccountState> SomeCommandSentToServerAsync(string key)
{
var taskCompletionSource = new TaskCompletionSource<AccountState>();
// Find a way to keep the task in some state somewhere
// so that you can get it the polling thread.
// Do the legacy WinSock Send() command.
return taskCompletionSource.Task;
}
// This would be, I guess, your polling thread.
// Again, I am sure it is not 100% accurate but
// it will hopefully give you an idea of where the key pieces must be.
private void PollingThread()
{
while(must_still_poll)
{
// Waits for some data to be available.
// Grabs the data.
if(this_is_THE_response)
{
// Get the response and built the account state somehow...
AccountState accountState = ...
// Key piece #1
// Grab the TaskCompletionSource instance somewhere.
// Key piece #2
// This is the magic line:
taskCompletionSource.SetResult(accountState);
// You can also do the following if something goes wrong:
// taskCompletionSource.SetException(new Exception());
}
}
}
Related
I need to do something like the following code. Note, this does not work due to the nature of locks in .Net (which I'll address after the code) but I need some form of implementation like this that works, but I don't know what to do.
static object lockMethod = new object();
static object lockTask = new object();
public static string testLocksAndTasks()
{
//This method is fast executing code but to prevent other issues, I
//lock this method. This might be impertinent to the base need of this
//question, but since I do use a lock on the entire requesting method, I
//put it here. This is because I integrate some logging and a bit of
//other logic on static variables so I just lock the method. This entire
//function is fast. The really slow code is in
//DoWorkInOtherThreadMethod(), which is why it needs to run in a
//background task.
lock (lockMethod)
{
if (Monitor.TryEnter(lockTask))
{
Task.Run(DoWorkInOtherThreadMethod)
.ContinueWith(ct=>
Monitor.Exit(lockTask)); //Oop! Unlocking on separate task NOT ALLOWED!
return "We locked lockTask and started the thread!";
}
else return "Task called and executed by other request!";
}
}
The above code gets the point across for what I'm trying to accomplish. I need to have a method (that is executed from a web request) and I need to test if a launched task from the request is already running in another thread. If it isn't running, I need to create the lock for the task (lockTask in this example) and prevent future calls while it runs, and report ack to the caller the state of the background task. If the lockTask is already in use, I specifically need to return "Task X is already running for Y item". (Note, I didn't include that extra information for what's already running, but that's not difficult to do and not required for this example.)
My code could theoretically work because once the entire task is finished, the call to ContinueWith() would unlock the lock for the task. However, what I've found is that this throws errors because the initial lock on lockTask is created in one thread, and then the subsequent unlock with Monitor.Exit(lockTask) is occurring on another thread and that's not allowed.
I could try to restructure my code to some thing like the code provided below, but this also has issues for my needs.
public static string testLocksAndTasks()
{
lock (lockMethod)
{
//Check if we're locked!
if (!Monitor.IsEntered(lockTask))
{
Task.Run(()=>
{
//We weren't locked, so TryEnter...
if (Monitor.TryEnter(lockTask))
{
DoWorkInOtherThreadMethod();
Monitor.Exit(lockTask); //NOTE: I KNOW THIS SHOULD BE WRAPPED IN A
//TRY/CATCH/FINALLY. I'm just keeping sample
//the code simple.
}
else
{
//Oh no! This is actually quite possible, but this is a case I never
//want to reach?! I can't report this back to the initial call to
//testLocksAndTasks since we are in a new thread!
}
});
return "We locked lockTask and started the thread!";
}
else return "Task called and executed by other request!";
}
}
My comment above outlines the obvious problem. I can create my task lock within the task and this fixes the first issue with the lock and exits happening on separate threads. However, this introduces a different but still important issue.
Since this code can execute semi-simultaneously across multiple request threads, there is a chance that there might be multiple calls to !Monitor.IsEntered(lockTask) returning true because the lock is not set until the Monitor.TryEnter(...) request is made within a new task. This wouldn't be an issue, however, I now can't return a proper state response to testLocksAndTasks().
How can I properly implement something like this where I lock a long running task but can also report if it's running?
Sounds like you don't need a lock but a simple flag indicating whether task is running. Now to read and set this flag you can use regular lock. So you check the flag and start the task if necessary inside the lock. When task is done you again set the flag inside the lock. Sample code:
static object lockTask = new object();
private static bool taskRunning = false;
public static string testLocksAndTasks()
{
lock (lockTask)
{
// check inside the lock
if (!taskRunning)
{
Task.Run(DoWorkInOtherThreadMethod)
.ContinueWith(ct =>
{
lock (lockTask)
{
// reset flag inside the lock
taskRunning = false;
}
});
// start task and set the flag
taskRunning = true;
return "We locked lockTask and started the thread!";
}
else return "Task called and executed by other request!";
}
}
I am looking for a way to cancel a task that was already started and then restart the same task with new input data.
Below is the sample code which I have written but it is not working.
private CancellationTokenSource _cancellationTokenSource;
public public async Task DoSomething(string input)
{
_cancellationTokenSource.Cancel(true);
_cancellationTokenSource = new CancellationTokenSource();
try
{
Task.Run(async () =>
{
//Asynchronous method code here which uses input like database operations.
await doSomeDataBaseOperationAsync(input);
}, _cancellationTokenSource.Token);
}
catch { }
}
Can someone help me with it?
You need to make a manual check in your method doSomeDataBaseOperationAsync which is getting executed asynchronously as shown in the code snippet below. The way I usually do is check the state of the cancellation token source once at the starting of the method itself. If cancellation is not requested till that time then just go ahead and execute the entire function body.
But nobody can stop you from making that check at more critical junctures or milestones inside your method e.g. you might want to recheck the cancellation token state once before firing the DB call as well.
Word of Caution: You just need to make sure that whenever you make such a check several time during the execution of the method and returning mid way then you aren't leaving the state of your object in an inconsistent state. If you don't alter any member variables of your class in such a method then you should be good.
private void doSomeDataBaseOperationAsync(input)
{
if (_cancellationTokenSource.IsCancellationRequested)
return; //stop any further processing.
//do some processing and calculations on the client side
//.....
//.....
//.....
//make a check again before firing DB request
if (_cancellationTokenSource.IsCancellationRequested)
return; //stop any further processing.
//Do database stuff. cancellation has not been requested. Process the DB request.
}
I am trying to get the proper 'structure' for monitoring the state of a game from external source(s) using (Tasks) async/await in order to run the tasks in an infinite loop, however the current way its written seems to just freeze up my UI.
What I have so far:
(in the "state machine" class)
// Start monitoring the game state for changes
public void Start()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
IsRunning = true;
task = Task.Factory.StartNew(async () =>
{
while (true)
{
await Task.Run(()=>CheckForStateChange());
await Task.Delay(1000); // Pause 1 second before checking state again
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
}
Without the above "Task.Delay" line the UI completely freezes up. With the "Task.Delay" line it doesn't freeze up, but if I try to drag the window it skips back to where I began dragging it.
My assumption with the current code is that the 'await Task.Run()' executes and upon completion the 'await Task.Delay()' executes and then on completion returns to the beginning of the while(true) infinite loop. (ie. not running in parallel).
The CheckForStateChange() signature is as follows:
private void CheckForStateChange()
{
// ... A bunch of code to determine and update the current state value of the object
}
Nothing special there, simple non-async method. I have read through lots of examples / questions here on StackOverflow and I used to have CheckForStateChange as returning a Task (with awaitable actions inside the method) and many other iterations of code (with the same results).
Finally I call the Start() method from the main win32 form (button) as follows:
private void btnStartSW_Click(object sender, EventArgs e)
{
// Start the subscription of the event handler
if(!state.IsRunning)
{
state.StateChange += new SummonersWar.StateChangeHandler(OnGameStateChange);
state.Start();
}
}
I think the above code is the simplest form I have written the code structure in so far, but apparently its still not written 'properly'. Any help would be appreciated.
UPDATE:
The publisher side (state machine class):
// ------ Publisher of the event ---
public delegate void StateChangeHandler(string stateText);
public event StateChangeHandler StateChange;
protected void OnStateChange() // TODO pass text?
{
if (StateChange != null)
StateChange(StateText());
}
Where the StateText() method is just a temporary way of retrieving a 'text' representation of the current state (and is really a placeholder at this point until I organize it into a tidier struct)
IsRunning is purely a public bool.
And the handler in the UI thread:
private void OnGameStateChange(string stateText)
{
// Game State Changed (update the status bar)
labelGameState.Text = "State: " + stateText;
}
Why the UI freezes
In terms of the main question: you're already calling your CheckForStateChange via Task.Run, so there is no way that your CheckForStateChange will freeze the UI unless it includes calls which are marshalled back to the UI thread (i.e. Control.Invoke or SynchronizationContext.Post/Send used explicitly, or implicitly via a Task started on the UI TaskScheduler).
The best place to start looking is your StateChange handlers (i.e. StateChangeHandler). Also have a look at where the StateChange event is raised. You'll find thread marshalling code at one of these sites.
Other issues
You're passing the TaskScheduler pointing to the UI SynchronizationContext to the outer task. You're also passing in TaskCreationOptions.LongRunning. In simple terms you're telling the task factory to "start a task on a dedicated thread, and on the current thread". These two are mutually exclusive requirements and you can pretty safely drop them both.
If, as a result of the above, your outer task happens to execute on the UI thread, it won't really trip you up as the inner call is wrapped in Task.Run, but this probably isn't the behaviour you expect.
You are storing the result of Task.Factory.StartNew inside a task field or property. Note, however, that your Task.Factory.StartNew call returns a Task<Task>, so the saved Task instance will transition to completed state almost immediately unless you call Unwrap on it and get to the inner task. To avoid this entire mess, just use Task.Run to create the outer task (as it has Unwrap semantics built in). If you do that, you can ditch the inner Task.Run completely, like so:
public bool IsRunning
{
get
{
return task.Status == TaskStatus.Running;
}
}
public void Start()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
task = Task.Run(async () =>
{
while (true)
{
CheckForStateChange(token);
token.ThrowIfCancellationRequested();
await Task.Delay(1000); // Pause 1 second before checking state again
}
}, token);
// Uncomment this and step through `CheckForStateChange`.
// When the execution hangs, you'll know what's causing the
// postbacks to the UI thread and *may* be able to take it out.
// task.Wait();
}
Since you have a CancellationToken you need to be passing it to CheckForStateChange, and checking it periodically - otherwise it only gets checked once, when the Task is started, and then never again.
Note that I have also provided a different IsRunning implementation. Volatile state is hard to get right. If the framework is giving it to you for free, you should use it.
Final word
Overall this entire solution feels like a bit of a crutch for something that should be done more reactively - but I can think of scenarios where this sort of design is valid. I'm just not convinced that yours is really one of them.
EDIT: how to find what's blocking the UI
I'll get downvoted to oblivion for this, but here goes:
The sure way to find what's causing postbacks to the UI thread is to deadlock with it. There's plenty of threads here on SO telling you how to avoid that, but in your case - we'll cause it on purpose and you'll know exactly what calls you need to avoid when you're polling for changes - although whether or not it will be possible to avoid these calls, remains to be seen.
I've put a task.Wait instruction at the end of my code snippet. Provided that you call Start on the UI thread, that should cause a deadlock with something inside your CheckForStateChange, and you will know what it is that you need to work around.
I have an ASP.NET MVC 3 site that connects to a WCF service. The WCF Service is independent from the site and is hosted in a Windows Service.
Most of the calls are synchronous, so it's not a problem to wait for the WCF to do it's thing.
However, one of those (already implemented) calls takes a bit too long, and, as it essentially does not output anything directly, I wanted to spin it on the service and forget about it.
So I changed my code from:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
to
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
which, as I understand should start an asynchronous request, and return immediately. Still, the execution is completely synchronous, and the UI is frozen until the operation concludes.
What obvious thing am I missing?
Update:
Also, note that I would prefer not to change the server implementation to an async one, just to de-synchronize the call to the service on the call-site.
Moreover, I've noticed that the StartSlowCalculation method finishes executing, but the server does not return a response until the service method finishes executing.
The WCF Service Proxy just does:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
so it's completely synchronous, however that shouldn't matter as it should be executed on an independent thread.
A task operation can run in the calling thread, it depends on taskScheduler decision. To help TaskScheduler make a right decision regarding long running call you can specify task creation option TaskCreationOptions.LongRunning.
And you can check whether task operation is running in a separate thread:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
BTW, are you using any kind of Task.Wait() operation? It will block calling thread as well.
EDIT:
You might find following post interesting Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
So try out using Task.Factory.StartNew() and specify cancellation token even you do not need it, sounds weird but it seems this guarantees that task will not be run eventually in the calling thread. Correct me If I wrong.
I've done this before.
The most robust way would be to use Asynchronous Controller's, or better yet an independant service such as a WCF service.
But in my experience, i've just needed to do "simple", one-liner task, such as auditing or reporting.
In that example, the easy way - fire off a Task:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
That's a simple example. You can fire off as many tasks as you want, synchronize them, get notified when they finish, etc.
For more details you can see this links.
https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
I have created a Windows 8 Metro App based on the Split Page sample app. However, in the sample app the data is loaded synchronously in the constructor. I'm accessing a text file and therefore need to load the data asynchronously. The constructor looks like this:
public MyDataSource()
{
DataLoaded = false;
LoadData();
}
LoadData() is an asynchronous method that populates the data model. This works fine, and displays the data as is loads it (which is the behavior that I want). The problem occurs when I try testing the suspend and terminate. The problem being that the recovery has the potential to attempt to access the data model before it is populated:
public static MyDataGroup GetGroup(string uniqueId)
{
// If the data hasn't been loaded yet then what?
if (_myDataSource == null)
{
// Where app has been suspended and terminated there is no data available yet
}
// Simple linear search is acceptable for small data sets
var matches = _myDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
I can fix this by changing the constructor to call LoadData().Wait, but this means that the app locks the UI thread. What I believe I need is a method of getting the recovery code in GetGroup to wait until the data has loaded without locking the UI thread. Is this possible or advisable, and if so, how?
EDIT:
One or two people have suggested caching the task for LoadData(). This is an excellent idea, but the code inside GetGroup is called by the Page State Management section and therefore cannot be async. To get around this, I tried the following:
if (!DataLoaded)
{
//dataLoading = await MyDataSource.LoadData();
dataLoading.RunSynchronously();
}
But this gives me an error:
RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
and
dataLoading.Wait()
just locks the UI.
I think that this sounds like the best option would be if you made the constructor async. But since that's not possible, what you can do instead is to create an async factory method for MyDataSource:
private MyDataSource()
{
DataLoaded = false;
}
public static async Task<MyDataSource> Create()
{
var source = new MyDataSource();
await source.LoadData();
return source;
}
And then initialize _myDataSource using await:
_myDataSource = await MyDataSource.Create();
If, for some reason, you can't do that, you can store the Task returned by the factory method and wait for it in GetGroup():
_myDataSourceTask = MyDataSource.Create();
…
public static async Task<MyDataGroup> GetGroup(string uniqueId)
{
var myDataSource = await _myDataSourceTask;
// Simple linear search is acceptable for small data sets
var matches = myDataSource.AllGroups.Where(group => group.UniqueId == uniqueId);
if (matches.Count() == 1) return matches.First();
return null;
}
If LoadData is async, then store whatever the awaitable is (or make a new one) and expose that (for instance, like a Task) then GetGroup can be marked async and can do var data = await _myDataSource.LoadTask or whatever
I think Svick is the closest to answering the question because of his use of Tasks. Whether you return a Task on the GetGroup method or you return a task on a LoadAsync method probably doesn't matter. What DOES matter is that you capture that task and refer to it later on resume.
The Task class is documented here and you'll notice it has properties like IsCanceled, IsCompleted and IsFaulted. When your constructor kicks off the LoadAsync method you could save the Task it returns as a class-level variable. Later, when your resume code starts, you can check to see whether the Task is still running (i.e. not completed and not faulted). If the Task has completed, you can run your resume code right away. If it hasn't completed yet, you can use Task.ContinueWith to schedule your resume code to be run when the task completes.
I did not check out Windows 8 yet, but I assume it works similar to Windows Phone, assuming you use Silverlight (or WPF) to develop your app, this is not clear to me from your question. In case you use Silverlight:
You need to use the INotifyPropertyChanged interface, and ObservableCollection-s to be able to bind your data to the UI. That way everytime you change your data, the UI will be notified about the changes, and bindings will refresh.
MyDataGroup a pubic property that implements iNotifyPropertyChanged.
UniqueID a public property.
When UniqueID changes set MyDataGroup = null then call a BackGroundWorker to var mathces = but delay that if LoadData(); is working. Since this is in the background the delay will not tie up the UI. In the callback set MyDataGroup and the UI will get notified. Make sure you backgroundworker is cancelable as you will want to cancel it when UniqueID is changed (if it is running).
I do this in WPF so if it does not translate to Metro sorry and I will delete.