Action queue manager to perform action in a FIFO fashionAction queue in .NET 3.5MVC Async Action Invoking WorkflowCall Action every X cyclesA queue that switches from FIFO mode to priority modeOptimizing a thread safe Java NIO / Serialization / FIFO QueueFileSystemWatcher with threaded FIFO processing(Optionally Concurrent) FIFOThread-safe bounded buffer FIFO queue using C++11Queue manager. Multithreading management implementationC# TCP server/client class
Are CO₂ tire cartridges reusable for multiple tires?
Kingdom Map and Travel Pace
Kerning feedback on logo
Why is the T-1000 humanoid?
Why did they ever make smaller than full-frame sensors?
Were Roman public roads build by private companies?
What is a realistic time needed to get a properly trained army?
How do email clients "send later" without storing a password?
Job offer without any details but asking me to withdraw other applications - is it normal?
How do you build a Dominant 7th chord?
Will replacing a fake visa with a different fake visa cause me problems when applying for a legal study permit?
How to help my 2.5-year-old daughter take her medicine when she refuses to?
Creating a Master Image to roll out to 30 new Machines Licensing Issues
„nichts wie raus hier“ - explanation based on the literal meaning?
How to work with a technician hired with a grant who argues everything
Why did it become so much more expensive to start a university?
Can I toggle Do Not Disturb on/off on my Mac as easily as I can on my iPhone?
Which ping implementation is Cygwin using?
Is it appropriate for a professor to require students to sign a non-disclosure agreement before being taught?
Can I disable a battery powered device by reversing half of its batteries?
Can a magnet rip protons from a nucleus?
Long list of Hit and Get from sudo apt update
Can the UK veto its own extension request?
A Little Riddle
Action queue manager to perform action in a FIFO fashion
Action queue in .NET 3.5MVC Async Action Invoking WorkflowCall Action every X cyclesA queue that switches from FIFO mode to priority modeOptimizing a thread safe Java NIO / Serialization / FIFO QueueFileSystemWatcher with threaded FIFO processing(Optionally Concurrent) FIFOThread-safe bounded buffer FIFO queue using C++11Queue manager. Multithreading management implementationC# TCP server/client class
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
Recently, I needed a class that could execute code in a FIFO fashion in order to update parts of a WinForms or WPF UI which did not block the UI Thread and left the UI responsive to any interaction the user did on it.
To achieve that objective, I developed the following code, which meets its requirements and performs decently enough to not be a burden.
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading;
namespace Rayffer.PersonalPortfolio.QueueManagers
public class BackgroundWorkerActionQueueManager : IDisposable
public bool IsBusy get; private set;
private BlockingCollection<Action> actionQueue;
private readonly BackgroundWorker backgroundWorker;
private CancellationTokenSource cancellationTokenSource;
public BackgroundWorkerActionQueueManager()
backgroundWorker = new BackgroundWorker();
actionQueue = new BlockingCollection<Action>();
cancellationTokenSource = new CancellationTokenSource();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += BackgroundWorker_ManageQueue;
backgroundWorker.RunWorkerAsync();
public void EnqueueAction(Action actionToEnqueue)
actionQueue.Add(actionToEnqueue);
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
Action actionToPerform = null;
try
IsBusy = false;
actionToPerform = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException ex)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
if (actionToPerform != null)
actionToPerform.Invoke();
actionToPerform = null;
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
backgroundWorker.CancelAsync();
cancellationTokenSource.Cancel();
backgroundWorker.DoWork -= BackgroundWorker_ManageQueue;
cancellationTokenSource.Dispose();
backgroundWorker.Dispose();
disposedValue = true;
public void Dispose()
Dispose(true);
This code can be used to perform any action enqueued, from doing a simple sum, to manipulating members of a class ensuring that the operations are carried out in the order they are enqueued.
I was wondering which optimisations I can apply to this code or if there are any bad practices or missusages of the classes.
An example of use would be the following
public class BackGroundWorkerActionQueueManagerTest
private BackgroundWorkerActionQueueManager sorterActionQueueManager = new BackgroundWorkerActionQueueManager ();
private BackgroundWorkerActionQueueManager sorterVisualizerActionQueueManager = new BackgroundWorkerActionQueueManager ();
private bool sorterHasEnded = false;
public Sorter sorter get;
public void StartSorterQueueTest(int[] arrayToSort)
sorterActionQueueManager.EnqueueAction(() =>
sorter.SortAscending(arrayToSort);
sorterHasEnded = true;
);
public void StartSorterQueueVisualisation()
sorterVisualizerActionQueueManager.EnqueueAction(() =>
while(!sorterHasEnded)
Thread.Sleep(100);
// Perform operations to visualise the sorting here
);
```
c# multithreading asynchronous
$endgroup$
add a comment |
$begingroup$
Recently, I needed a class that could execute code in a FIFO fashion in order to update parts of a WinForms or WPF UI which did not block the UI Thread and left the UI responsive to any interaction the user did on it.
To achieve that objective, I developed the following code, which meets its requirements and performs decently enough to not be a burden.
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading;
namespace Rayffer.PersonalPortfolio.QueueManagers
public class BackgroundWorkerActionQueueManager : IDisposable
public bool IsBusy get; private set;
private BlockingCollection<Action> actionQueue;
private readonly BackgroundWorker backgroundWorker;
private CancellationTokenSource cancellationTokenSource;
public BackgroundWorkerActionQueueManager()
backgroundWorker = new BackgroundWorker();
actionQueue = new BlockingCollection<Action>();
cancellationTokenSource = new CancellationTokenSource();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += BackgroundWorker_ManageQueue;
backgroundWorker.RunWorkerAsync();
public void EnqueueAction(Action actionToEnqueue)
actionQueue.Add(actionToEnqueue);
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
Action actionToPerform = null;
try
IsBusy = false;
actionToPerform = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException ex)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
if (actionToPerform != null)
actionToPerform.Invoke();
actionToPerform = null;
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
backgroundWorker.CancelAsync();
cancellationTokenSource.Cancel();
backgroundWorker.DoWork -= BackgroundWorker_ManageQueue;
cancellationTokenSource.Dispose();
backgroundWorker.Dispose();
disposedValue = true;
public void Dispose()
Dispose(true);
This code can be used to perform any action enqueued, from doing a simple sum, to manipulating members of a class ensuring that the operations are carried out in the order they are enqueued.
I was wondering which optimisations I can apply to this code or if there are any bad practices or missusages of the classes.
An example of use would be the following
public class BackGroundWorkerActionQueueManagerTest
private BackgroundWorkerActionQueueManager sorterActionQueueManager = new BackgroundWorkerActionQueueManager ();
private BackgroundWorkerActionQueueManager sorterVisualizerActionQueueManager = new BackgroundWorkerActionQueueManager ();
private bool sorterHasEnded = false;
public Sorter sorter get;
public void StartSorterQueueTest(int[] arrayToSort)
sorterActionQueueManager.EnqueueAction(() =>
sorter.SortAscending(arrayToSort);
sorterHasEnded = true;
);
public void StartSorterQueueVisualisation()
sorterVisualizerActionQueueManager.EnqueueAction(() =>
while(!sorterHasEnded)
Thread.Sleep(100);
// Perform operations to visualise the sorting here
);
```
c# multithreading asynchronous
$endgroup$
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you haveIsBusy.
$endgroup$
– VisualMelon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago
add a comment |
$begingroup$
Recently, I needed a class that could execute code in a FIFO fashion in order to update parts of a WinForms or WPF UI which did not block the UI Thread and left the UI responsive to any interaction the user did on it.
To achieve that objective, I developed the following code, which meets its requirements and performs decently enough to not be a burden.
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading;
namespace Rayffer.PersonalPortfolio.QueueManagers
public class BackgroundWorkerActionQueueManager : IDisposable
public bool IsBusy get; private set;
private BlockingCollection<Action> actionQueue;
private readonly BackgroundWorker backgroundWorker;
private CancellationTokenSource cancellationTokenSource;
public BackgroundWorkerActionQueueManager()
backgroundWorker = new BackgroundWorker();
actionQueue = new BlockingCollection<Action>();
cancellationTokenSource = new CancellationTokenSource();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += BackgroundWorker_ManageQueue;
backgroundWorker.RunWorkerAsync();
public void EnqueueAction(Action actionToEnqueue)
actionQueue.Add(actionToEnqueue);
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
Action actionToPerform = null;
try
IsBusy = false;
actionToPerform = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException ex)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
if (actionToPerform != null)
actionToPerform.Invoke();
actionToPerform = null;
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
backgroundWorker.CancelAsync();
cancellationTokenSource.Cancel();
backgroundWorker.DoWork -= BackgroundWorker_ManageQueue;
cancellationTokenSource.Dispose();
backgroundWorker.Dispose();
disposedValue = true;
public void Dispose()
Dispose(true);
This code can be used to perform any action enqueued, from doing a simple sum, to manipulating members of a class ensuring that the operations are carried out in the order they are enqueued.
I was wondering which optimisations I can apply to this code or if there are any bad practices or missusages of the classes.
An example of use would be the following
public class BackGroundWorkerActionQueueManagerTest
private BackgroundWorkerActionQueueManager sorterActionQueueManager = new BackgroundWorkerActionQueueManager ();
private BackgroundWorkerActionQueueManager sorterVisualizerActionQueueManager = new BackgroundWorkerActionQueueManager ();
private bool sorterHasEnded = false;
public Sorter sorter get;
public void StartSorterQueueTest(int[] arrayToSort)
sorterActionQueueManager.EnqueueAction(() =>
sorter.SortAscending(arrayToSort);
sorterHasEnded = true;
);
public void StartSorterQueueVisualisation()
sorterVisualizerActionQueueManager.EnqueueAction(() =>
while(!sorterHasEnded)
Thread.Sleep(100);
// Perform operations to visualise the sorting here
);
```
c# multithreading asynchronous
$endgroup$
Recently, I needed a class that could execute code in a FIFO fashion in order to update parts of a WinForms or WPF UI which did not block the UI Thread and left the UI responsive to any interaction the user did on it.
To achieve that objective, I developed the following code, which meets its requirements and performs decently enough to not be a burden.
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading;
namespace Rayffer.PersonalPortfolio.QueueManagers
public class BackgroundWorkerActionQueueManager : IDisposable
public bool IsBusy get; private set;
private BlockingCollection<Action> actionQueue;
private readonly BackgroundWorker backgroundWorker;
private CancellationTokenSource cancellationTokenSource;
public BackgroundWorkerActionQueueManager()
backgroundWorker = new BackgroundWorker();
actionQueue = new BlockingCollection<Action>();
cancellationTokenSource = new CancellationTokenSource();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += BackgroundWorker_ManageQueue;
backgroundWorker.RunWorkerAsync();
public void EnqueueAction(Action actionToEnqueue)
actionQueue.Add(actionToEnqueue);
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
Action actionToPerform = null;
try
IsBusy = false;
actionToPerform = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException ex)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
if (actionToPerform != null)
actionToPerform.Invoke();
actionToPerform = null;
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
backgroundWorker.CancelAsync();
cancellationTokenSource.Cancel();
backgroundWorker.DoWork -= BackgroundWorker_ManageQueue;
cancellationTokenSource.Dispose();
backgroundWorker.Dispose();
disposedValue = true;
public void Dispose()
Dispose(true);
This code can be used to perform any action enqueued, from doing a simple sum, to manipulating members of a class ensuring that the operations are carried out in the order they are enqueued.
I was wondering which optimisations I can apply to this code or if there are any bad practices or missusages of the classes.
An example of use would be the following
public class BackGroundWorkerActionQueueManagerTest
private BackgroundWorkerActionQueueManager sorterActionQueueManager = new BackgroundWorkerActionQueueManager ();
private BackgroundWorkerActionQueueManager sorterVisualizerActionQueueManager = new BackgroundWorkerActionQueueManager ();
private bool sorterHasEnded = false;
public Sorter sorter get;
public void StartSorterQueueTest(int[] arrayToSort)
sorterActionQueueManager.EnqueueAction(() =>
sorter.SortAscending(arrayToSort);
sorterHasEnded = true;
);
public void StartSorterQueueVisualisation()
sorterVisualizerActionQueueManager.EnqueueAction(() =>
while(!sorterHasEnded)
Thread.Sleep(100);
// Perform operations to visualise the sorting here
);
```
c# multithreading asynchronous
c# multithreading asynchronous
edited 9 hours ago
dfhwze
11.3k2 gold badges22 silver badges75 bronze badges
11.3k2 gold badges22 silver badges75 bronze badges
asked 12 hours ago
Oscar GuillamonOscar Guillamon
4426 silver badges18 bronze badges
4426 silver badges18 bronze badges
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you haveIsBusy.
$endgroup$
– VisualMelon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago
add a comment |
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you haveIsBusy.
$endgroup$
– VisualMelon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you have
IsBusy.$endgroup$
– VisualMelon
11 hours ago
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you have
IsBusy.$endgroup$
– VisualMelon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
EnqueueAction may want to throw an ObjectDisposedException if the queue is disposed, depending on the precise API you want.
I don't see the value of IsBusy, and it won't be cleared if the task is cancelled.
I little padding inside the while loop would make that code much easier to understand. I'd be temped to pull the logic for retrieving the next action out into its own method so that it can read more clearly:
if (TryGetNextAction(out Action nextAction))
// invoke etc.
else
break;
This will make it easier to extend and modify the conditions under which the worker should terminate. You could make it a local function if you want to prevent misuse.
For example, cancellationTokenSource.Token could throw an ObjectDisposedException, which should probably be a case where you fail cleanly, but handling this logic would clutter the existing method.
You never change any of your private members, so you might consider making them readonly. Alternatively you might consider setting them to null upon disposal. Implementation of IDispose looks standard, and I think disposing the BackgroundWorker there is OK, but I'm less than certain.
Some inline documentation would help to confirm the precise API this class is providing, and should clarify things like "if the object is disposed, then pending tasks are dropped", and "order of operations is FIFO as observed from a single thread", etc. BackGroundWorkerActionQueueManagerTest doesn't really elucidate its behaviour.
$endgroup$
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing theCancellationTokenSourcewill invalided it, and the call toTokenmay duly fail. (i.e.var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token;will throw)
$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
add a comment |
$begingroup$
I think, I would provide the CancellationToken to each action, in order to let them respond to a possible cancellation request. Especially if the action is long running it would be a good idea.
BlockingCollection<Action<CancellationToken>> actionQueue
while(!sorterHasEnded)
Thread.Sleep(100);
This tells me, that you are in the need for a mechanism that tells you when each queued action has finished. May be an event. You could then bind each action to a user defined Id of some kind and signal that, when the action is completed:
private BlockingCollection<ActionItem> actionQueue;
public void EnqueueAction(string id, Action<CancellationToken> actionToEnqueue)
if (string.IsNullOrWhiteSpace(id)) new ArgumentException("Can not be empty or null", nameof(id));
if (actionToEnqueue == null) new ArgumentNullException(nameof(actionToEnqueue));
actionQueue.Add(new ActionItem(id, actionToEnqueue));
And the background worker could be as something like:
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
ActionItem actionItem;
try
IsBusy = false;
actionItem = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
actionItem.Action(cancellationTokenSource.Token);
OnActionEnded(actionItem.Id);
public event EventHandler<ActionEndedEventArgs> ActionEnded;
private void OnActionEnded(string id)
ActionEnded?.Invoke(this, new ActionEndedEventArgs(id));
Where ActionItem is defined as:
class ActionItem
public ActionItem(string id, Action<CancellationToken> action)
Id = id;
Action = action;
public string Id get;
public Action<CancellationToken> Action get;
Maybe the ActionEnded event should be fired in a separate thread in order to not block the execution queue while a client responds to it?
$endgroup$
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in aThreadPoolthread?
$endgroup$
– Henrik Hansen
8 hours ago
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f227781%2faction-queue-manager-to-perform-action-in-a-fifo-fashion%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
EnqueueAction may want to throw an ObjectDisposedException if the queue is disposed, depending on the precise API you want.
I don't see the value of IsBusy, and it won't be cleared if the task is cancelled.
I little padding inside the while loop would make that code much easier to understand. I'd be temped to pull the logic for retrieving the next action out into its own method so that it can read more clearly:
if (TryGetNextAction(out Action nextAction))
// invoke etc.
else
break;
This will make it easier to extend and modify the conditions under which the worker should terminate. You could make it a local function if you want to prevent misuse.
For example, cancellationTokenSource.Token could throw an ObjectDisposedException, which should probably be a case where you fail cleanly, but handling this logic would clutter the existing method.
You never change any of your private members, so you might consider making them readonly. Alternatively you might consider setting them to null upon disposal. Implementation of IDispose looks standard, and I think disposing the BackgroundWorker there is OK, but I'm less than certain.
Some inline documentation would help to confirm the precise API this class is providing, and should clarify things like "if the object is disposed, then pending tasks are dropped", and "order of operations is FIFO as observed from a single thread", etc. BackGroundWorkerActionQueueManagerTest doesn't really elucidate its behaviour.
$endgroup$
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing theCancellationTokenSourcewill invalided it, and the call toTokenmay duly fail. (i.e.var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token;will throw)
$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
add a comment |
$begingroup$
EnqueueAction may want to throw an ObjectDisposedException if the queue is disposed, depending on the precise API you want.
I don't see the value of IsBusy, and it won't be cleared if the task is cancelled.
I little padding inside the while loop would make that code much easier to understand. I'd be temped to pull the logic for retrieving the next action out into its own method so that it can read more clearly:
if (TryGetNextAction(out Action nextAction))
// invoke etc.
else
break;
This will make it easier to extend and modify the conditions under which the worker should terminate. You could make it a local function if you want to prevent misuse.
For example, cancellationTokenSource.Token could throw an ObjectDisposedException, which should probably be a case where you fail cleanly, but handling this logic would clutter the existing method.
You never change any of your private members, so you might consider making them readonly. Alternatively you might consider setting them to null upon disposal. Implementation of IDispose looks standard, and I think disposing the BackgroundWorker there is OK, but I'm less than certain.
Some inline documentation would help to confirm the precise API this class is providing, and should clarify things like "if the object is disposed, then pending tasks are dropped", and "order of operations is FIFO as observed from a single thread", etc. BackGroundWorkerActionQueueManagerTest doesn't really elucidate its behaviour.
$endgroup$
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing theCancellationTokenSourcewill invalided it, and the call toTokenmay duly fail. (i.e.var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token;will throw)
$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
add a comment |
$begingroup$
EnqueueAction may want to throw an ObjectDisposedException if the queue is disposed, depending on the precise API you want.
I don't see the value of IsBusy, and it won't be cleared if the task is cancelled.
I little padding inside the while loop would make that code much easier to understand. I'd be temped to pull the logic for retrieving the next action out into its own method so that it can read more clearly:
if (TryGetNextAction(out Action nextAction))
// invoke etc.
else
break;
This will make it easier to extend and modify the conditions under which the worker should terminate. You could make it a local function if you want to prevent misuse.
For example, cancellationTokenSource.Token could throw an ObjectDisposedException, which should probably be a case where you fail cleanly, but handling this logic would clutter the existing method.
You never change any of your private members, so you might consider making them readonly. Alternatively you might consider setting them to null upon disposal. Implementation of IDispose looks standard, and I think disposing the BackgroundWorker there is OK, but I'm less than certain.
Some inline documentation would help to confirm the precise API this class is providing, and should clarify things like "if the object is disposed, then pending tasks are dropped", and "order of operations is FIFO as observed from a single thread", etc. BackGroundWorkerActionQueueManagerTest doesn't really elucidate its behaviour.
$endgroup$
EnqueueAction may want to throw an ObjectDisposedException if the queue is disposed, depending on the precise API you want.
I don't see the value of IsBusy, and it won't be cleared if the task is cancelled.
I little padding inside the while loop would make that code much easier to understand. I'd be temped to pull the logic for retrieving the next action out into its own method so that it can read more clearly:
if (TryGetNextAction(out Action nextAction))
// invoke etc.
else
break;
This will make it easier to extend and modify the conditions under which the worker should terminate. You could make it a local function if you want to prevent misuse.
For example, cancellationTokenSource.Token could throw an ObjectDisposedException, which should probably be a case where you fail cleanly, but handling this logic would clutter the existing method.
You never change any of your private members, so you might consider making them readonly. Alternatively you might consider setting them to null upon disposal. Implementation of IDispose looks standard, and I think disposing the BackgroundWorker there is OK, but I'm less than certain.
Some inline documentation would help to confirm the precise API this class is providing, and should clarify things like "if the object is disposed, then pending tasks are dropped", and "order of operations is FIFO as observed from a single thread", etc. BackGroundWorkerActionQueueManagerTest doesn't really elucidate its behaviour.
answered 10 hours ago
VisualMelonVisualMelon
6,13714 silver badges41 bronze badges
6,13714 silver badges41 bronze badges
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing theCancellationTokenSourcewill invalided it, and the call toTokenmay duly fail. (i.e.var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token;will throw)
$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
add a comment |
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing theCancellationTokenSourcewill invalided it, and the call toTokenmay duly fail. (i.e.var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token;will throw)
$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
In which conditions the token can throw an object disposed exception? I hold a reference to it throughout the whole lifetime of the class, as it is intended only to cancel the .Take()
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
It's a public class, other consumers could use it in a way the lifetime is handled differently than you intended, so you should guard against it.
$endgroup$
– dfhwze
8 hours ago
$begingroup$
@OscarGuillamon disposing the
CancellationTokenSource will invalided it, and the call to Token may duly fail. (i.e. var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token; will throw)$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@OscarGuillamon disposing the
CancellationTokenSource will invalided it, and the call to Token may duly fail. (i.e. var cts = new CancellationTokenSource(); cts.Dispose(); var t = cts.Token; will throw)$endgroup$
– VisualMelon
8 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
@dfhwze but the token is private, which is only disposed at the object's disposal itself, I fail to see what's wrong, can you further expand please?
$endgroup$
– Oscar Guillamon
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
$begingroup$
there can be a race condition in which Dispose already disposed the token while BackgroundWorker_ManageQueue still uses it one last time.
$endgroup$
– dfhwze
7 hours ago
add a comment |
$begingroup$
I think, I would provide the CancellationToken to each action, in order to let them respond to a possible cancellation request. Especially if the action is long running it would be a good idea.
BlockingCollection<Action<CancellationToken>> actionQueue
while(!sorterHasEnded)
Thread.Sleep(100);
This tells me, that you are in the need for a mechanism that tells you when each queued action has finished. May be an event. You could then bind each action to a user defined Id of some kind and signal that, when the action is completed:
private BlockingCollection<ActionItem> actionQueue;
public void EnqueueAction(string id, Action<CancellationToken> actionToEnqueue)
if (string.IsNullOrWhiteSpace(id)) new ArgumentException("Can not be empty or null", nameof(id));
if (actionToEnqueue == null) new ArgumentNullException(nameof(actionToEnqueue));
actionQueue.Add(new ActionItem(id, actionToEnqueue));
And the background worker could be as something like:
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
ActionItem actionItem;
try
IsBusy = false;
actionItem = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
actionItem.Action(cancellationTokenSource.Token);
OnActionEnded(actionItem.Id);
public event EventHandler<ActionEndedEventArgs> ActionEnded;
private void OnActionEnded(string id)
ActionEnded?.Invoke(this, new ActionEndedEventArgs(id));
Where ActionItem is defined as:
class ActionItem
public ActionItem(string id, Action<CancellationToken> action)
Id = id;
Action = action;
public string Id get;
public Action<CancellationToken> Action get;
Maybe the ActionEnded event should be fired in a separate thread in order to not block the execution queue while a client responds to it?
$endgroup$
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in aThreadPoolthread?
$endgroup$
– Henrik Hansen
8 hours ago
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
add a comment |
$begingroup$
I think, I would provide the CancellationToken to each action, in order to let them respond to a possible cancellation request. Especially if the action is long running it would be a good idea.
BlockingCollection<Action<CancellationToken>> actionQueue
while(!sorterHasEnded)
Thread.Sleep(100);
This tells me, that you are in the need for a mechanism that tells you when each queued action has finished. May be an event. You could then bind each action to a user defined Id of some kind and signal that, when the action is completed:
private BlockingCollection<ActionItem> actionQueue;
public void EnqueueAction(string id, Action<CancellationToken> actionToEnqueue)
if (string.IsNullOrWhiteSpace(id)) new ArgumentException("Can not be empty or null", nameof(id));
if (actionToEnqueue == null) new ArgumentNullException(nameof(actionToEnqueue));
actionQueue.Add(new ActionItem(id, actionToEnqueue));
And the background worker could be as something like:
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
ActionItem actionItem;
try
IsBusy = false;
actionItem = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
actionItem.Action(cancellationTokenSource.Token);
OnActionEnded(actionItem.Id);
public event EventHandler<ActionEndedEventArgs> ActionEnded;
private void OnActionEnded(string id)
ActionEnded?.Invoke(this, new ActionEndedEventArgs(id));
Where ActionItem is defined as:
class ActionItem
public ActionItem(string id, Action<CancellationToken> action)
Id = id;
Action = action;
public string Id get;
public Action<CancellationToken> Action get;
Maybe the ActionEnded event should be fired in a separate thread in order to not block the execution queue while a client responds to it?
$endgroup$
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in aThreadPoolthread?
$endgroup$
– Henrik Hansen
8 hours ago
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
add a comment |
$begingroup$
I think, I would provide the CancellationToken to each action, in order to let them respond to a possible cancellation request. Especially if the action is long running it would be a good idea.
BlockingCollection<Action<CancellationToken>> actionQueue
while(!sorterHasEnded)
Thread.Sleep(100);
This tells me, that you are in the need for a mechanism that tells you when each queued action has finished. May be an event. You could then bind each action to a user defined Id of some kind and signal that, when the action is completed:
private BlockingCollection<ActionItem> actionQueue;
public void EnqueueAction(string id, Action<CancellationToken> actionToEnqueue)
if (string.IsNullOrWhiteSpace(id)) new ArgumentException("Can not be empty or null", nameof(id));
if (actionToEnqueue == null) new ArgumentNullException(nameof(actionToEnqueue));
actionQueue.Add(new ActionItem(id, actionToEnqueue));
And the background worker could be as something like:
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
ActionItem actionItem;
try
IsBusy = false;
actionItem = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
actionItem.Action(cancellationTokenSource.Token);
OnActionEnded(actionItem.Id);
public event EventHandler<ActionEndedEventArgs> ActionEnded;
private void OnActionEnded(string id)
ActionEnded?.Invoke(this, new ActionEndedEventArgs(id));
Where ActionItem is defined as:
class ActionItem
public ActionItem(string id, Action<CancellationToken> action)
Id = id;
Action = action;
public string Id get;
public Action<CancellationToken> Action get;
Maybe the ActionEnded event should be fired in a separate thread in order to not block the execution queue while a client responds to it?
$endgroup$
I think, I would provide the CancellationToken to each action, in order to let them respond to a possible cancellation request. Especially if the action is long running it would be a good idea.
BlockingCollection<Action<CancellationToken>> actionQueue
while(!sorterHasEnded)
Thread.Sleep(100);
This tells me, that you are in the need for a mechanism that tells you when each queued action has finished. May be an event. You could then bind each action to a user defined Id of some kind and signal that, when the action is completed:
private BlockingCollection<ActionItem> actionQueue;
public void EnqueueAction(string id, Action<CancellationToken> actionToEnqueue)
if (string.IsNullOrWhiteSpace(id)) new ArgumentException("Can not be empty or null", nameof(id));
if (actionToEnqueue == null) new ArgumentNullException(nameof(actionToEnqueue));
actionQueue.Add(new ActionItem(id, actionToEnqueue));
And the background worker could be as something like:
private void BackgroundWorker_ManageQueue(object sender, DoWorkEventArgs e)
while (!backgroundWorker.CancellationPending)
ActionItem actionItem;
try
IsBusy = false;
actionItem = actionQueue.Take(cancellationTokenSource.Token);
IsBusy = true;
catch (OperationCanceledException)
// This exception control intends to capture only when the cancellationToken has been requested to cancel
break;
actionItem.Action(cancellationTokenSource.Token);
OnActionEnded(actionItem.Id);
public event EventHandler<ActionEndedEventArgs> ActionEnded;
private void OnActionEnded(string id)
ActionEnded?.Invoke(this, new ActionEndedEventArgs(id));
Where ActionItem is defined as:
class ActionItem
public ActionItem(string id, Action<CancellationToken> action)
Id = id;
Action = action;
public string Id get;
public Action<CancellationToken> Action get;
Maybe the ActionEnded event should be fired in a separate thread in order to not block the execution queue while a client responds to it?
answered 8 hours ago
Henrik HansenHenrik Hansen
12.2k1 gold badge17 silver badges42 bronze badges
12.2k1 gold badge17 silver badges42 bronze badges
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in aThreadPoolthread?
$endgroup$
– Henrik Hansen
8 hours ago
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
add a comment |
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in aThreadPoolthread?
$endgroup$
– Henrik Hansen
8 hours ago
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
How would you go about firing 'actionended' on a separate thread
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in a
ThreadPool thread?$endgroup$
– Henrik Hansen
8 hours ago
$begingroup$
@OscarGuillamon: Wouldn't it be possible in a
ThreadPool thread?$endgroup$
– Henrik Hansen
8 hours ago
1
1
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
$begingroup$
Yeah, that's what I was thinking about, Ive not worked a lot with threadpool threads, so I'll give it a shot and read about it
$endgroup$
– Oscar Guillamon
8 hours ago
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f227781%2faction-queue-manager-to-perform-action-in-a-fifo-fashion%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Could you provide an example or explanation of how you would expect to use this? In particular, I'm clear why you have
IsBusy.$endgroup$
– VisualMelon
11 hours ago
$begingroup$
I added an example of how I expect the class to be used, hope it is enough as it is just a proof of concept.
$endgroup$
– Oscar Guillamon
11 hours ago