C# Producer/Consumer implementation issue - c#

I have a producer-consumer class as following.
public class ProducerConsumer<T> where T : class
{
private Thread _workerThread;
private readonly Queue<T> _workQueue;
private readonly object _lockObject = new object();
private readonly Action<T> _workCallbackAction;
private ManualResetEvent _workerWaitSignal;
public ProducerConsumer(Action<T> action)
{
_workCallbackAction = action;
_workQueue = new Queue<T>();
}
private void DoWork()
{
while (true)
{
T workItemToBeProcessed = default(T);
bool hasSomeWorkItem = false;
lock (_lockObject)
{
hasSomeWorkItem = _workQueue.Count > 0;
if (hasSomeWorkItem)
{
workItemToBeProcessed = _workQueue.Dequeue();
if (workItemToBeProcessed == null)
{
return;
}
}
}
if (hasSomeWorkItem)
{
if (_workCallbackAction != null)
{
_workCallbackAction(workItemToBeProcessed);
}
}
else
{
_workerWaitSignal.WaitOne();
Debug.WriteLine("Waiting for signal.");
}
}
}
public void EnQueueWorkItem(T workItem)
{
lock (_lockObject)
{
_workQueue.Enqueue(workItem);
_workerWaitSignal.Set();
}
}
public void StopWork(ManualResetEvent stopSignal)
{
EnQueueWorkItem(null);
_workerThread.Join();
_workerWaitSignal.Close();
_workerWaitSignal = null;
if (stopSignal != null)
{
stopSignal.Set();
}
}
public void ReStart()
{
_workerWaitSignal = new ManualResetEvent(false);
_workerThread = new Thread(DoWork) { IsBackground = true };
_workerThread.Start();
}
}
and i am using this in the following way:
public partial class Form1 : Form
{
private RecordProducerConsumer<string> _proConsumer;
public Form1()
{
InitializeComponent();
_proConsumer = new RecordProducerConsumer<string>(DoAction);
}
private bool restart=true;
private int item = 0;
private void button1_Click(object sender, EventArgs e)
{
if (restart)
{
_proConsumer.ReStart();
restart = false;
}
item++;
_proConsumer.EnQueueWorkItem(item.ToString());
}
private void DoAction(string str)
{
Debug.WriteLine(str);
}
private void btnStop_Click(object sender, EventArgs e)
{
ManualResetEvent mre = new ManualResetEvent(false);
_proConsumer.StopWork(mre);
mre.WaitOne();
restart = true;
}
private void Stop(ManualResetEvent mre)
{
mre.WaitOne();
}
}
My problem or what I can not understand is when I click Start button I am adding only one item and it Dequeue that item but keeps on running the loop so I see lot of "Waiting for signal." print outs on the Output window in Visual Studio.
Why does it not stop on _workerWaitSignal.WaitOne(); in DoWork() method , why is it running all the time ?

Couple of issues:
It makes hardly any sense to output 'Waiting for issue' after executing the wait. Consider moving the write before the actual wait.
You are using a ManualResetEvent — as its name indicates, it requires a manual reset to revert from the signalled state. However, I can't see a call to Reset in your code.
To avoid other concurrency issues (e.g. a race condition when when resetting the event while other thread set the event after enqueuing another work item), consider using a Semaphore for your scenario instead.

try this... I could be wrong...but that is all i could figure out by reading through your code. Hope this helps :)
private void button1_Click(object sender, EventArgs e)
{
if (restart)
{
restart = false;
_proConsumer.ReStart();
}
item++;
_proConsumer.EnQueueWorkItem(item.ToString());
}

I haven't read the code thoroughly, but I can venture a guess that you meant to use an AutoResetEvent (which resets automatically after some WaitOne() is released) rather than a ManualResetEvent (which stays set until you explicitly call Reset()).
Also, is there any reason you're not using .NET's BlockingCollection<T> ? It's the framework implementation of the producer/consumer pattern, and it works very well.

Related

How to correctly update a property of an object from a BackgroundWorker launched in the code of a methode of this object?

Don't now if title is clear. Here is a piece of code from a class in charge of managing a long operation :
public class LongProcess
{
public delegate void RunningChangedEventHandler(bool running);
public event RunningChangedEventHandler RunningChanged;
private object runningLock = new object();
public bool Running
{
get { lock (runningLock) { return mRunning; } }
set
{
lock (runningLock)
{
RunningChanged.Invoke(value);
value = mRunning;
}
}
}
public void start()
{
mWorker = new BackgroundWorker();
mWorker.DoWork += Bg_DoWork;
mWorker.RunWorkerAsync();
}
private void Bg_DoWork(object sender, DoWorkEventArgs e)
{
Running = true;
// Some things to do here ... but I need Running to be equals to true and it is not
}
}
In main programm, I use LongProcess to start some tasks, it is completed by report progression etc ...
The only problem I'm facing, is that it seems that I'm unable to set "Running" to true. Even right after the call to the setter, it still keeps its old value.
Any help and explanations on how this works will be greatly appreciated !
You have your value and field the wrong way around in the setter. You need this:
public bool Running
{
get { lock (runningLock) { return mRunning; } }
set
{
lock (runningLock)
{
RunningChanged.Invoke(value);
mRunning = value; // <=== LOOK HERE
}
}
}

Background worker c# stop worker - immediately (include Thread.Sleep in DoWork)

i want to just stop my backgroundworker when i press a button :
Code looking like :
Button :
private void button6_Click(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
if (isOn == true)
{
isOn = false;
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
this.button6.ForeColor = System.Drawing.Color.Lime;
}
}
else
{
isOn = true;
this.button6.ForeColor = System.Drawing.Color.Red;
backgroundWorker1.CancelAsync();
//////backgroundWorker1.Dispose();
}
And my Backgroundworker_DoWork look like :
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (backgroundWorker1.CancellationPending && backgroundWorker1.IsBusy)
{
e.Cancel = true;
return;
}
while (true)
{
if (backgroundWorker1.CancellationPending && backgroundWorker1.IsBusy)
{
e.Cancel = true;
break;
}
backgroundWorker1.Dispose();
click_na_default(hwnd1);
click_F8(hwnd1);
click_na_YELLS(hwnd1);
click_ENTER(hwnd1);
Thread.Sleep(100);
click_na_trade(hwnd1);
Thread.Sleep(100);
click_F8(hwnd1);
click_ENTER(hwnd1);
Thread.Sleep(100);
click_na_default(hwnd1);
Thread.Sleep(4000);
}
if (((BackgroundWorker)sender).CancellationPending)
{
e.Cancel = true;
//set this code at the end of file processing
return;
}
}
And the problem is : I can't .CancelAsync(); just immediately after button press again . My code just DoWork untill just Thread.Sleep(4000); is over.
When i press my button to stop work this gonna stop just after end while loop.
I know i can add
if (backgroundWorker1.CancellationPending && backgroundWorker1.IsBusy)
{
e.Cancel = true;
return;
}
After everyline in my Backgroundworker_DoWork but it's so stupid and when i get Thread.Sleep(10000); it gonna takes 10 sec...
Is any way to just kill instantly my background worker?
Thanks for help!
I think that standard BackgroundWorker is not suitable for your case and you should do something custom that better support combination of sleep and cancellation. Following code is an idea of what you might want to do:
CancellableBackgroundWorker.cs
This is a class similar to standard BackgroundWorker but providing some callbacks for your goal (see ICancellationProvider and FinishedEvent).
public delegate void CancellableBackgroundJob(ICancellationProvider cancellation);
public interface ICancellationProvider
{
bool CheckForCancel();
void CheckForCancelAndBreak();
void SleepWithCancel(int millis);
}
public class CancellableBackgroundWorker : Component, ICancellationProvider
{
private readonly ManualResetEvent _canceledEvent = new ManualResetEvent(false);
private readonly CancellableBackgroundJob _backgroundJob;
private volatile Thread _thread;
private volatile bool _disposed;
public EventHandler FinishedEvent;
public CancellableBackgroundWorker(CancellableBackgroundJob backgroundJob)
{
_backgroundJob = backgroundJob;
}
protected override void Dispose(bool disposing)
{
Cancel();
_disposed = true;
}
private void AssertNotDisposed()
{
if (_disposed)
throw new InvalidOperationException("Worker is already disposed");
}
public bool IsBusy
{
get { return (_thread != null); }
}
public void Start()
{
AssertNotDisposed();
if (_thread != null)
throw new InvalidOperationException("Worker is already started");
_thread = new Thread(DoWorkWrapper);
_thread.Start();
}
public void Cancel()
{
AssertNotDisposed();
_canceledEvent.Set();
}
private void DoWorkWrapper()
{
_canceledEvent.Reset();
try
{
_backgroundJob(this);
Debug.WriteLine("Worker thread completed successfully");
}
catch (ThreadAbortException ex)
{
Debug.WriteLine("Worker thread was aborted");
Thread.ResetAbort();
}
finally
{
_canceledEvent.Reset();
_thread = null;
EventHandler finished = FinishedEvent;
if (finished != null)
finished(this, EventArgs.Empty);
}
}
#region ICancellationProvider
// use explicit implementation of the interface to separate interfaces
// I'm too lazy to create additional class
bool ICancellationProvider.CheckForCancel()
{
return _canceledEvent.WaitOne(0);
}
void ICancellationProvider.CheckForCancelAndBreak()
{
if (((ICancellationProvider)this).CheckForCancel())
{
Debug.WriteLine("Cancel event is set, aborting the worker thread");
_thread.Abort();
}
}
void ICancellationProvider.SleepWithCancel(int millis)
{
if (_canceledEvent.WaitOne(millis))
{
Debug.WriteLine("Sleep aborted by cancel event, aborting the worker thread");
_thread.Abort();
}
}
#endregion
}
The main trick is to use ManualResetEvent.WaitOne instead of Thread.Sleep for sleeping. With such approach working thread might be safely woken up (for cancellation) from a different (UI) thread. Another trick is to use ThreadAbortException via Thread.Abort to enforce quick end of the background thread execution (and don't forget about Thread.ResetAbort at the end of stack unwinding).
You may use this class as following:
public partial class Form1 : Form
{
private readonly CancellableBackgroundWorker _backgroundWorker;
public Form1()
{
InitializeComponent();
_backgroundWorker = new CancellableBackgroundWorker(DoBackgroundJob);
_backgroundWorker.FinishedEvent += (s, e) => UpdateButton();
// ensure this.components is created either by InitializeComponent or by us explicitly
// so we can add _backgroundWorker to it for disposal
if (this.components == null)
this.components = new System.ComponentModel.Container();
components.Add(_backgroundWorker);
}
private void UpdateButton()
{
// Ensure we interact with UI on the main thread
if (InvokeRequired)
{
Invoke((Action)UpdateButton);
return;
}
button1.Text = _backgroundWorker.IsBusy ? "Cancel" : "Start";
}
private void button1_Click(object sender, EventArgs e)
{
if (_backgroundWorker.IsBusy)
{
_backgroundWorker.Cancel();
}
else
{
_backgroundWorker.Start();
}
UpdateButton();
}
private void DoBackgroundJob(ICancellationProvider cancellation)
{
Debug.WriteLine("Do something");
// if canceled, stop immediately
cancellation.CheckForCancelAndBreak();
Debug.WriteLine("Do something more");
if (cancellation.CheckForCancel())
{
// you noticed cancellation but still need to finish something
Debug.WriteLine("Do some necessary clean up");
return;
}
// Sleep but cancel will stop and break
cancellation.SleepWithCancel(10000);
Debug.WriteLine("Last bit of work");
}
}

User interaction in non-UI thread?

in my WPF - C# application, I have a time consuming function, which I execute with a BackgroundWorker. The job of this function is to add given data from a file into a database. Now and then, I need some user feedback, for example the data is already in the store and I want to ask the user, whether he wants to merge the data or create a new object or skip the data completely. Much like the dialog windows shows, if I try to copy a file to a location, where a file with the same name already exists.
The problem is, that I cannot call a GUI-window from a non GUI-thread. How could I implement this behavior?
Thanks in advance,
Frank
You could work with EventWaitHandle ou AutoResetEvent, then whenever you want to prompt the user, you could the signal UI, and then wait for the responde. The information about the file could be stored on a variable.
If possible... my suggestion is to architect your long running task into atomic operations. Then you can create a queue of items accessible by both your background thread and UI thread.
public class WorkItem<T>
{
public T Data { get; set; }
public Func<bool> Validate { get; set; }
public Func<T, bool> Action { get; set; }
}
You can use something like this class. It uses a queue to manage the execution of your work items, and an observable collection to signal the UI:
public class TaskRunner<T>
{
private readonly Queue<WorkItem<T>> _queue;
public ObservableCollection<WorkItem<T>> NeedsAttention { get; private set; }
public bool WorkRemaining
{
get { return NeedsAttention.Count > 0 && _queue.Count > 0; }
}
public TaskRunner(IEnumerable<WorkItem<T>> items)
{
_queue = new Queue<WorkItem<T>>(items);
NeedsAttention = new ObservableCollection<WorkItem<T>>();
}
public event EventHandler WorkCompleted;
public void LongRunningTask()
{
while (WorkRemaining)
{
if (_queue.Any())
{
var workItem = _queue.Dequeue();
if (workItem.Validate())
{
workItem.Action(workItem.Data);
}
else
{
NeedsAttention.Add(workItem);
}
}
else
{
Thread.Sleep(500); // check if the queue has items every 500ms
}
}
var completedEvent = WorkCompleted;
if (completedEvent != null)
{
completedEvent(this, EventArgs.Empty);
}
}
public void Queue(WorkItem<T> item)
{
// TODO remove the item from the NeedsAttention collection
_queue.Enqueue(item);
}
}
Your UI codebehind could look something like
public class TaskRunnerPage : Page
{
private TaskRunner<XElement> _taskrunner;
public void DoWork()
{
var work = Enumerable.Empty<WorkItem<XElement>>(); // TODO create your workItems
_taskrunner = new TaskRunner<XElement>(work);
_taskrunner.NeedsAttention.CollectionChanged += OnItemNeedsAttention;
Task.Run(() => _taskrunner.LongRunningTask()); // run this on a non-UI thread
}
private void OnItemNeedsAttention(object sender, NotifyCollectionChangedEventArgs e)
{
// e.NewItems contains items that need attention.
foreach (var item in e.NewItems)
{
var workItem = (WorkItem<XElement>) item;
// do something with workItem
PromptUser();
}
}
/// <summary>
/// TODO Use this callback from your UI
/// </summary>
private void OnUserAction()
{
// TODO create a new workItem with your changed parameters
var workItem = new WorkItem<XElement>();
_taskrunner.Queue(workItem);
}
}
This code is untested! But the basic principle should work for you.
Specifically to your case
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(1000);
var a = Test1("a");
Thread.Sleep(1000);
var b = (string)Invoke(new Func<string>(() => Test2("b")));
MessageBox.Show(a + b);
}
private string Test1(string text)
{
if (this.InvokeRequired)
return (string)this.Invoke(new Func<string>(() => Test1(text)));
else
{
MessageBox.Show(text);
return "test1";
}
}
private string Test2(string text)
{
MessageBox.Show(text);
return "test2";
}
Test2 is a normal method which you have to invoke from background worker. Test1 can be called directly and uses safe pattern to invoke itself.
MessageBox.Show is similar to yourForm.ShowDialog (both are modal), you pass parameters to it (text) and you return value (can be a value of property of yourForm which is set when form is closed). I am using string, but it can be any data type obviously.
From the input of the answers here, I came to the following solution:
(Mis)Using the ReportProgress-method of the Backgroundworker in Combination with a EventWaitHandle. If I want to interact with the user, I call the ReportProgress-method and setting the background process on wait. In the Handler for the ReportProgress event I do the interaction and when finished, I release the EventWaitHandle.
BackgroundWorker bgw;
public MainWindow()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.WorkerReportsProgress = true;
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
}
// Starting the time consuming operation
private void Button_Click(object sender, RoutedEventArgs e)
{
bgw.RunWorkerAsync();
}
// using the ProgressChanged-Handler to execute the user interaction
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UserStateData usd = e.UserState as UserStateData;
// UserStateData.Message is used to see **who** called the method
if (usd.Message == "X")
{
// do the user interaction here
UserInteraction wnd = new UserInteraction();
wnd.ShowDialog();
// A global variable to carry the information and the EventWaitHandle
Controller.instance.TWS.Message = wnd.TextBox_Message.Text;
Controller.instance.TWS.Background.Set();
}
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
// our time consuming operation
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(2000);
// need 4 userinteraction: raise the ReportProgress event and Wait
bgw.ReportProgress(0, new UserStateData() { Message = "X", Data = "Test" });
Controller.instance.TWS.Background.WaitOne();
// The WaitHandle was released, the needed information should be written to global variable
string first = Controller.instance.TWS.Message.ToString();
// ... and again
Thread.Sleep(2000);
bgw.ReportProgress(0, new UserStateData() { Message = "X", Data = "Test" });
Controller.instance.TWS.Background.WaitOne();
e.Result = first + Controller.instance.TWS.Message;
}
I hope I did not overlooked some critical issues. I'm not so familar with multithreading - maybe there should be some lock(object) somewhere?

variable not set by background worker on first pass

I have an observer with a background worker. Lets say the observer has the following structure:
internal class Observer
{
private readonly BackgroundWorker bw1;
internal Object target;
public Observer()
{
bw1 = new BackgroundWorker();
bw1.DoWork += bw1_DoWork;
bw1.RunWorkerCompleted += bw1_RunWorkerCompleted;
bw1.WorkerSupportsCancellation = true;
}
private void bw1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = new object(); // Query to database
}
private void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
target = e.Result as object;
if (ChangedScannedValue != null)
{
ChangedScannedValue(_scannedValue);
}
}
private String _scannedValue = string.Empty;
internal delegate void OnChangedScannedValue(String scannedValue);
internal event OnChangedScannedValue ChangedScannedValue;
internal String ScannedValue
{
get { return _scannedValue; }
set
{
_scannedValue = value;
bw1.RunWorkerAsync(_scannedValue);
//ProcessScannedValue();
}
}
}
I have another class listening to the event.
public partial class myControl : UserControl
{
Observer _observer = new Observer();
public myControl()
{
InitializeComponent();
}
internal void LoadData(Observer observer)
{
_observer = observer;
_observer.ChangedScannedValue += _observer_ChangedScannedValue;
}
void _observer_ChangedScannedValue(string ScannedValue)
{
if (_observer.target != null)
{
// Do Stuff
}
else
{
MessageBox.Show("NO TARGET FOUND.");
}
}
}
The thing is. initially, after the background worker finishes, I get the message box "NO TARGET FOUND.", however immediatley after, it would //Do Stuff Debugging shows that the RunWorkerCompleted event fires twice. This only happens on the first change to scanned value, all changes afterwards work as desired.
Questions:
1) Why does RunWorkerCompleted fire twice?
2) Why is the target not updated on the first fire of RunWorkerCompleted
You could try again with target being set in bw1_DoWork already, i.e.:
private void bw1_DoWork(object sender, DoWorkEventArgs e) {
target = new object(); // Query to database
}
private void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (ChangedScannedValue != null) {
ChangedScannedValue(_scannedValue);
}
}
Eventually you may want to replace the BackgroundWorker by a simpler solution with ThreadPool. I'd suggest this:
internal String ScannedValue {
get { return _scannedValue; }
set {
_scannedValue = value;
ThreadPool.QueueUserWorkItem( (WaitCallback) delegate {
target = new object(); // query database
if (ChangedScannedValue != null) ChangedScannedValue(_scannedValue);
} );
}
}

C#, how to avoid recursion elegantly?

I've got an event-function, where the code inside the function may trigger calling the same function again (because a message loop is used). How can I avoid this or better "detect" this most elegantly? When it comes to multiple thread synchronization one could write:
public void Closing(object sender, EventArgs e)
{
lock(m_Object)
{
<Code, which can trigger Closing again>
}
}
But in my case it is the same thread that may call the same function and thus lock fails to work.
Introduce a private bool m_IsClosing variable that indicates whether closing is already in progress.
public void Closing(object sender, EventArgs e)
{
lock (m_Object)
{
if (m_IsClosing)
return;
m_IsClosing = true;
try
{
// Code, which can trigger Closing again
}
finally
{
m_IsClosing = false;
}
}
}
I don't think it's particularly elegant, but without knowing more about what you're doing, I can't any better solution.
Edit: adapted example for possible exceptions while closing.
Add a member of your class closingInProgress initialized to false. Then:
public void Closing(object sender, EventArgs e)
{
if (closingInProgress)
{
return;
}
try
{
closingInProgress = true;
<Code, which can trigger Closing again>
}
finally
{
closingInProgress = false;
}
}
Use a private field to remember whether Closing has already been called. If it has, then abort from the procedure:
private bool ClosingDone;
public void Closing(object sender, EventArgs e)
{
if (!ClosingDone)
{
ClosingDone = true;
// Code, which can trigger Closing again
}
}
A simple solution is to have a flag available in your class which indicates the event is being handled. Using this flag, you can determine whether to run the method again when called recursively.
private bool m_IsClosing;
public void Closing(object sender, EventArgs e)
{
lock(m_Object)
{
// Check for state.
if(m_IsClosing)
return;
m_IsClosing = true;
try
{
// The rest of your code.
}
finally
{
m_IsClosing = false;
}
}
}
The only difficulty will be ensuring you don't read or modify this value elsewhere without entering a critical section locked on m_Object. Otherwise, it should prevent the event handler doing any work recursively.
It's a bit old, but how about that:
public class Locker : IDisposable
{
bool _isActive;
public bool IsActive
{
get { return _isActive; }
}
private Locker()
{
_isActive = false;
}
public static Locker Create()
{
return new Locker();
}
public void Dispose()
{
_isActive = false;
}
public Locker Activate()
{
_isActive = true;
return this;
}
}
usage:
Locker lo = Locker.Create();
private void Foo()
{
if (lo.IsActive) return;
using(lo.Activate())
{
Console.WriteLine("Foo");
Bar();
}
}
private void Bar()
{
Console.WriteLine("Bar");
Foo();
}
Method Foo() is only called once. using makes sure, that lo is deactivated, even if an error occures.

Categories

Resources