Multiple calls wait on the same async task - c#

Basically I have a lot of places in my app where in order to do something I need to make sure a product image is downloaded. I want to centralize this call into one place so I make sure to only download it once. I'm trying to do like this in my class:
private IAsyncOperation<bool> _downloadCoverTask;
internal IAsyncOperation<bool> DownloadCoverAsync()
{
if (this._downloadCoverTask == null)
{
this._downloadCoverTask = this._cloudProduct.Image.DownloadAsync();
}
return this._downloadCoverTask;
}
_cloudProduct.Image.DownloadAsync() is a method which actually does the image downloading (it also happens to be in a library that I don't control).
So in my code where I need to download the image, I do
await product.DownloadCoverAsync();
// do stuff with the image
This works ok the first time I call it, but the second time it's called I get the exception "A delegate was assigned when not allowed." I don't get any stack trace or anything either.
This would get called a bunch of places, but I'm hoping that they would all wait on the same task, and then continue when it's complete. If it's already completed I hope it would just return right away. It's possible that I'm misunderstanding and that's just not how it works?
(Yes, I posted this before, but wasn't able to get an answer and I think this question summarizes the issue better. There is also this question, but that uses TPL and seems to have a much more complex goal.)

Try to use a Task<bool> instead of an IAsyncOperation<bool>. You can get a task using the AsTask extension method.

Related

File.ReadAllText with a lambda-based retry wrapper on Try Catch

Trying to find the most elegant solution for a situation when I get a "IOException: Sharing violation" on loading a JSON file because it is being saved at the same time by another application.
Using a "try Catch' with some form of recursion when loading, though inelegant, makes sense.
So after searching came across this C# solution which gets a lot of up votes
Cleanest way to write retry logic?
The actual function call where my load occurs is
private static T LoadData<T>(string filePath)
{
return JsonUtility.FromJson<T>(File.ReadAllText(filePath));
}
However not sure how to implement using the above linked solution (Retry.Do) which doesn't seem to allow passed arguments in the function call ie
Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1));
Can anyone help?
You need to create a closure.
The simplest way is to use a lambda expression:
YourType data = Retry.Do(() => LoadData<YourType>("somefilepath"), TimeSpan.FromSeconds(1));

Self referencing loop while trying to use Hangfire

I'm developing an Web API in ASP.NET Core and we found ourselves in the need of running a background task for a large bulk insert operation. The model I'm inserting however contains a property of the Geometry type from the .NET Topology Suite.
public class GeometricData
{
//...
public Geometry Geometry { get; set; }
}
In order to bulk insert, I'm following a method I found here and it is quite performatic, but its implementation is beyond the scope of this question. Even though it is fast, an user could be inserting over one million records in one go for instance, so we decided to move this processing to a background task. The Hangfire extension looked like something that could save us a lot of time at first, but it doesn't seem to handle well the Geometry type. In the code below, the BackgroundTask method might as well be an empty method:
public Task BulkInsert(IEnumerable<GeometricData> list)
{
BackgroundJob.Enqueue(() => BackgroundTask(list));
return Task.CompletedTask;
}
Just the act of passing a list of Geometry as a parameter to BackgroundTask in the action for Enqueue will throw the unfortunate error:
Self referencing loop detected for property 'CoordinateValue' with type 'NetTopologySuite.Geometries.Coordinate'. Path '[0].Geometry.Coordinates[0]'.
As a matter of fact, Coordinates (a NTS class) does reference itself:
No idea why they would do that, but they did. Regardless, everything worked just fine up until now, but unless I manage to find a solution to this (or even maybe work my way around it), I'm gonna be in a heap of trouble implementing a background worker from scratch (I'll be using the Worker Service, in case anyone is wondering). Any pointers?
Man, Add JsonIgnoreAttribute above Geometry and Coordinates, additionally: check the following link: newtonsoft.com/json/help/html/PropertyJsonIgnore.htm

Concurrency of modifying a Roslyn workspace? How does Visual studio do it?

probably a stupid question, but: Is there any way to reliable apply changes to a Roslyn workspace concurrently? And if not, what is the best practice to ensure it's done in correct order?
Example: Say you have some solution loaded into a Workspace, and have a basic function that will add a new project to the solution:
private Workspace _workspace;
// This is not thread-safe, right?
void AddProject()
{
var project = _workspace.CurrentSolution.AddProject(/* ... */);
_workspace.TryApplyChanges(project.Solution);
}
First question: Correct me if wrong, but I think AddProject would not be thread-safe, is that correct?
For example, lets say you want to add to new projects concurrently. So you call AddProject() twice concurrently.
My understanding is there is a race condition, and you might end up with both projects added (if one of the calls completes TryApplyChanges before the other call reaches _workspace.CurrentSolution), or only one of the projects added (if both calls have reached _worksapce.CurrentSolution before either has executed TryApplyChanges).
Second question: If my understanding is correct, then is there any best way to avoid these concurrency issues? I suppose the only real way would be to schedule/execute each modification sequentually, right?
How does Visual Studio, for example, do this.. Are modifications to the Workspace e.g. only done on the Dispatcher?
Thanks
The underlying code is thread-safe, but your usage is not.
TryApplyChanges() will return false if the solution changed in the meantime. If that happens, you need to try the changes again (starting from the new CurrentSolution).
Basically, you need to write
Solution changed;
do {
changed = _workspace.CurrentSolution....();
} while (!_workspace.TryApplyChanges(changed);
This is called a compare-and-swap loop; see my blog for more details.

No closure for delegates in anonymous function inside foreach loop

UPDATE: turns out that this is a problem with the Mono compiler used by Unity3D. I'm not sure if the current version of Mono (3.10.0) fixes it, but the old version used in the engine (2.0.5) seems to not implement this feature for delegates, or simply work as it should.
At some point in a game I'm developing (in the Unity3D engine), the player unlocks several items at once. For each of them I must present a simple information dialog that the user must click to advance to the next, until all have been read.
I have a simple C# static method to show a dialog (just a colored overlay with some text in Unity, and NOT in any way related to C# UI frameworks):
ConfirmationDialog.Create("Item X Unlocked!", callback);
When the user finally presses the dialog, callback is called.
I wanted to chain all dialogs so that each one is only created when the previous is clicked on, so I tried this:
Action callback = delegate {};
foreach (string item in unlockedItems) {
var cb = callback; // I though this would create a closure for delegates too
callback = (() => ConfirmationDialog.Create(item + " Unlocked!", cb));
}
callback();
This made sense in my head, as the anonymous function would use a different "cb" delegate in each iteration of the cycle. It seems I'm mistaken, though, as this code seems to result in the same dialog being repeatedly called when clicked, as would happen in a recursive function (which I guess is what it became).
I know I can, for example, do int value = i; inside a for loop (where i is the loop iterator) to use the correct value of i inside the anonymous function (I found a lot of material on this). Delegates seem different, but what in particular makes them not work in the same way? Or am I doing something terribly wrong? Could I do this chaining in some similar way? I say "similar" because I can certainly think of doing this in other - more complicated - ways...
Note: please DO correct me if my use of the words "closure", "delegate", etc, is not right :)
Do you have control over the ConfirmationDialog.Create("Item X Unlocked!", callback); API? If so, instead of taking a callback, you should look at refactoring that to use Task. If you had that, you could simply chain a bunch of tasks as continuations and have them execute one after the other.
I know with game development, these things are often quite asynchronous in nature, the way UI gets shown and subsequently reacted to ... so you could use TaskCompletionSource so you have a handle to something that you can signal that your task is done.

Lockless list help!

Hi im trying to write a lockless list i got the adding part working it think but the code that extracts objects from the list does not work to good :(
Well the list is not a normal list.. i have the Interface IWorkItem
interface IWorkItem
{
DateTime ExecuteTime { get; }
bool Cancelled { get; }
void Execute(DateTime now);
}
and well i have a list where i can add this :P and the idear is when i run Get(); on the list it should loop it until it finds a IWorkItem that
If (item.ExecuteTime < DateTime.Now)
and remove it from the list and return it..
i have ran tests with many threads on my dual core cpu and it seems that Add works never failed so far but the Get function looses some workitems some where i have no idear whats wrong.....
ps if i get this working any one is free to use the code :) well you are any way but i dont se the point when its bugged :P
The code is here http://www.easy-share.com/1903474734/LinkedList.zip and if you try to run it you will see that it will some times not be able to get as many workitems as it did put in the list...
Edit: I have got a lockless list working it was faster than using the lock(obj) statment but i have a lock object that uses Interlocked that was still outpreforming the lockless list, im going to try to make a lockless arraylist and se if i get the same results there when im done ill upload the result here..
The problem is your algorithm: Consider this sequence of events:
Thread 1 calls list.Add(workItem1), which completes fully.
Status is:
first=workItem1, workItem1.next = null
Then thread 1 calls list.Add(workItem2) and reaches the spot right before the second Replace (where you have the comment "//lets try").
Status is:
first=workItem1, workItem1.next = null, nextItem=workItem1
At this point thread 2 takes over and calls list.Get(). Assume workItem1's executionTime is now, so the call succeeds and returns workItem1.
After this status is:
first = null, workItem1.next = null
(and in the other thread, nextItem is still workItem1).
Now we get back to the first thread, and it completes the Add() by setting workItem1.next:=workItem2.
If we call list.Get() now, we will get null, even though the Add() completed successfully.
You should probably look up a real peer-reviewed lock-free linked list algorithm. I think the standard one is this by John Valois. There is a C++ implementation here. This article on lock-free priority queues might also be of use.
You can use a timestamping protocol for datastructures just fine, mirroring this example from the database world:
Concurrency
But be clear that each item needs both a read and write timestamp, and be sure to follow the rules of the algorithm clearly.
There are some additional difficulties of implementing this on a linked list though, I think. The database example would be fine for a vector where you know the array index of what you want. However, in a linked list, you may need to walk down the pointers -- and the structure of the list could change while you are searching! I guess you could solve that by some sort of nuance (or if you just want to traverse the "new" list as it is, do nothing), but it poses a problem. Try to solve it without introducing some rollback condition that makes it worse than locking the list!
So are you sure that it needs to be lockless? Depending on your work load the non-blocking solution can sometimes be slower. Check out this MSDN article for a little more. Also proving that a lockless data structure is correct can be very difficult.
I am in no way an expert on the subject, but as far as I can see, you need to either make the ExecutionTime-field in the implementation of IWorkItem volatile (of course it might already be that) or insert a memorybarrier either after you set the ExecutionTime or before you read it.

Categories

Resources