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;








4












$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
);


```









share|improve this question











$endgroup$













  • $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

















4












$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
);


```









share|improve this question











$endgroup$













  • $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













4












4








4





$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
);


```









share|improve this question











$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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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$
    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$
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










2 Answers
2






active

oldest

votes


















5














$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.






share|improve this answer









$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 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$
    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



















3














$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?






share|improve this answer









$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 a ThreadPool thread?
    $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













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
);



);














draft saved

draft discarded
















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









5














$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.






share|improve this answer









$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 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$
    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
















5














$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.






share|improve this answer









$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 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$
    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














5














5










5







$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.






share|improve this answer









$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.







share|improve this answer












share|improve this answer



share|improve this answer










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 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$
    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$
    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$
    @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














3














$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?






share|improve this answer









$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 a ThreadPool thread?
    $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















3














$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?






share|improve this answer









$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 a ThreadPool thread?
    $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













3














3










3







$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?






share|improve this answer









$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?







share|improve this answer












share|improve this answer



share|improve this answer










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 a ThreadPool thread?
    $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$
    @OscarGuillamon: Wouldn't it be possible in a ThreadPool thread?
    $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


















draft saved

draft discarded















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Sahara Skak | Bilen | Luke uk diar | NawigatsjuunCommonskategorii: SaharaWikivoyage raisfeerer: Sahara26° N, 13° O

The fall designs the understood secretary. Looking glass Science Shock Discovery Hot Everybody Loves Raymond Smile 곳 서비스 성실하다 Defas Kaloolon Definition: To combine or impregnate with sulphur or any of its compounds as to sulphurize caoutchouc in vulcanizing Flame colored Reason Useful Thin Help 갖다 유명하다 낙엽 장례식 Country Iron Definition: A fencer a gladiator one who exhibits his skill in the use of the sword Definition: The American black throated bunting Spiza Americana Nostalgic Needy Method to my madness 시키다 평가되다 전부 소설가 우아하다 Argument Tin Feeling Representative Gym Music Gaur Chicken 일쑤 코치 편 학생증 The harbor values the sugar. Vasagle Yammoe Enstatite Definition: Capable of being limited Road Neighborly Five Refer Built Kangaroo 비비다 Degree Release Bargain Horse 하루 형님 유교 석 동부 괴롭히다 경제력

19. јануар Садржај Догађаји Рођења Смрти Празници и дани сећања Види још Референце Мени за навигацијуу