I have written a DirectSoundWrapper but I just can access the interfaces through MTA Threads.
So I created a Thread that is working in background and executes actions in a queue.
I've done something like this:
private void MTAQueue()
{
lock (queueLockObj)
{
do
{
if (marshalThreadItems.Count > 0)
{
MarshalThreadItem item;
item = marshalThreadItems.Dequeue();
item.Action();
}
else
{
Monitor.Wait(queueLockObj);
}
} while (!disposing);
}
}
And I Execute an Action like this:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj);
}
}
}
But now I wanted to wait for the finishing the action is called. So I wanted to use a ManuelResetEvent:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
item.waitHandle = new ManualResetEvent(false); //setup
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj); //here the pulse does not pulse my backgrond thread anymore
item.waitHandle.WaitOne(); //waiting
}
}
}
And my background thread i just edit like this:
item.Action();
item.waitHandle.Set();
The problem is that the background thread does not get pulsed anymore and just keeps waiting (Monitor.Wait(queueLockObj)) and my mainthread that calls the action waits on the manuelresetevent...?
Why?
Problem in your code is that before Monitor.Wait(queueLockObj) will exit and thread can process item another thread (ExecuteMTAAction method) must call Monitor.Exit(queueLockObj), but call to item.waitHandle.WaitOne() is preventing this call - and you have dead lock. So - you must call Monitor.Exit(queueLockObj) before item.waitHandle.WaitOne().
This code will work fine:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
item.waitHandle = new ManualResetEvent(false); //setup
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj);
}
item.waitHandle.WaitOne(); //waiting
}
}
Related
Consider the following:
//base stuff
private readonly ConcurrentQueue<message> queue = new ConcurrentQueue<message>();
private readonly MyCacheData _cache = new MyCacheData ();
//setuo
timer = new Timer { Interval = 60_000, AutoReset = true };
timer.Elapsed += OnTimedEvent;
httpClient.Timeout = new TimeSpan(0, 0, 60); // 60 seconds too
//
// each 60 seconds
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (cache 30 minutes old)
{
//Fire and Forget GetWebDataAsync()
// and continue executing next stuff
// if I await it will wait 60 seconds worst case
// until going to the queue and by this time another
// timed even fires
}
// this always should execute each 60 seconds
if (queue isnt empty)
{
process queue
}
}
// heavy cache update each 10-30 minutes
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
}
finally
{
release Semaphore
}
}
}
Colored: https://ghostbin.com/paste/6edov
Because I cheat and use the cheap ConcurrentQueue solution I don't really care much about what happens during GetWebDataAsync(), I just want to fire it and do its job, while I instantly go to process queue because it always must be done each 60 seconds or timer resolution.
How do I correctly do that, avoid much overhead or unnecessary thread spawning?
EDIT: got an answer for my case elsewhere
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
async void DoGetWebData() => await GetWebDataAsync()
if (condition)
{
DoGetWebData(); // Fire&Forget and continue, exceptions handled inside
}
//no (a)waiting for the GetWebDataAsync(), we already here
if (queue isnt empty)
{
//process queue
}
}
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
//log stuff
}
finally
{
///always release lock
}
}
}
Task.Run(...);
ThreadPool.QueueUserItem(...);
Anything wrong with these?...
How about something like that:
ManualResetEvent mre = new ManualResetEvent(false);
void Foo()
{
new Thread(() =>
{
while (mre.WaitOne())
{
/*process queue item*/
if (/*queue is empty*/)
{
mre.Reset();
}
}
}) { IsBackground = true }.Start();
}
void AddItem()
{
/*queue add item*/
mre.Set();
}
Call an async method from another async method without await statement
Prepared for downvotes but I am really nowhere near getting to grips with the ins and outs of threading with this backgroundworker, but I've managed to just about get a structure for what I want:
public class cls1
{
private FormProgress myProgForm = new FormProgress();
public BackgroundWorker worker = new BackgroundWorker(); // new instance of bkgworker
public void prepare_a_job()
{
worker.WorkerReportsProgress = true; // Allows the worker to report progress
worker.ProgressChanged += worker_ProgressChanged; // Adding handler to update progress
worker.DoWork += job1; // Adding handler for the ACTUAL JOB METHOD
myProgForm.Show(); // Show the prog update form
worker.RunWorkerAsync(); // Start the job, already! Wo lo loo
}
void job1(object sender, EventArgs e) // Do 0 to 100
{
for (int i = 0; i <= 100; i++)
{
(sender as BackgroundWorker).ReportProgress(i); // ReportProgress uses percentages
Thread.Sleep(50);
}
// THIS IS WHERE I'D INSERT ANOTHER METHOD
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if(e.ProgressPercentage == 100) // If the % gets to 100
{
myProgForm.UPDATEME("", true); // then pass true to close progressForm
}
else
{
myProgForm.UPDATEME("Counting\n" + e.ProgressPercentage); // else just update
}
}
}
And on my FormProgress I just have this method:
public void UPDATEME(string MSG, bool finish = false)
{
this.label1.Text = MSG;
this.Refresh();
if (finish) { this.Close(); }
}
Messy, right? But it works (and I've been trying to find/learn this stuff for 24 hours and this is the first thing I even remotely understand.
The issue I'm having with this mess, is calling the UPDATEME() method from any other methods I want to call during the job1 routine - e.g. in reality this won't just be a loop to waste time, it'll be a set of conditions to call a tonne of other methods in various orders.
I tried bunging in a 2nd method into job1 and within that 2nd method call UPDATEME but it's not a thread-safe cross-thread update...
I think it might have something to do with Invoking but then I also read something about MSDN BackgroundWorker was another way to allow thread-safe without invoke and then my head exploded and my brain fell out.
How can I always refer to my ProgressForm.UPDATEME("new progress message") method within any other method in my code?
EDIT:
For instance I'd insert a call to this 2nd method in the job1 call
void myOtherMethod()
{
(worker).ReportProgress(0);
myProgForm.UPDATEME("Doing part 1");
Thread.Sleep(1000);
myProgForm.UPDATEME("Doing part 2");
Thread.Sleep(1000);
myProgForm.UPDATEME("Doing part 3");
Thread.Sleep(1000);
}
How can I always refer to my ProgressForm.UPDATEME("new progress
message") method within any other method in my code?
Like this:
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => this.UPDATEME(MSG, finish)));
}
else
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}
}
I don't really understand how invoking the method from within itself
gets round the fact the method is called outside the 1st level
thread ...
It is confusing at first as this is a recursive call. The "meat" is that Invoke() runs whatever is inside it on the same thread that created the control (the form itself in this case). When we enter the method the second time (due to recursion) the check returns false and we safely run the else block on the UI thread.
You can actually get rid of the check (and recursion) by always calling Invoke() whether it's needed or not like this:
public void UPDATEME(string MSG, bool finish = false)
{
this.Invoke(new Action(() =>
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}));
}
Here is an alternate version that still checks if Invoke() is required, but doesn't use recursion (less confusing, but we've now introduced duplicate code):
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}));
}
else
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}
}
For those that are "detail oriented", here is an approach/variation (I'm using MethodInvoker instead of Action) showing one way to remove the duplicate code above:
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
this.updater(MSG, finish);
});
}
else
{
this.updater(MSG, finish);
}
}
private void updater(string MSG, bool finish = false) // NOT thread safe, thus the private (don't call directly)
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}
I am trying to have my listbox clear it self at the end of my thread. I am having issues invoking it and was hoping someone would show me how.
public delegate void ClearDelegate(ListBox lb);
public void ItemClear(ListBox lb)
{
if (lb.InvokeRequired)
{
lb.Invoke(new ClearDelegate(ItemClear), new Object[] { lb });
}
listBox1.Items.Clear();
}
Quite trivial example using it's own thread (attention just for showing, better here would maybe a BackgroundWorker!):
private Thread _Thread;
public Form1()
{
InitializeComponent();
_Thread = new Thread(OnThreadStart);
}
private void OnButton1Click(object sender, EventArgs e)
{
var state = _Thread.ThreadState;
switch (state)
{
case ThreadState.Unstarted:
_Thread.Start(listBox1);
break;
case ThreadState.WaitSleepJoin:
case ThreadState.Running:
_Thread.Suspend();
break;
case ThreadState.Suspended:
_Thread.Resume();
break;
}
}
private static void OnThreadStart(object obj)
{
var listBox = (ListBox)obj;
var someItems = Enumerable.Range(1, 10).Select(index => "My Item " + index).ToArray();
foreach (var item in someItems)
{
listBox.Invoke(new Action(() => listBox.Items.Add(item)));
Thread.Sleep(1000);
}
listBox.Invoke(new Action(() => listBox.Items.Clear()));
}
According to the MSDN documentation
it is enought to put listBox1.Items.Clear(); statement into else statement.
Another thing is that you can use asynchronous method BeginInvoke that do not block the thread to wait for method finish.
Listbox can be accessed only by the UI thread and not the worker thread.
var sync = SynchronizatoinContext.Current;
sync.Post(delegate {
// Perform UI related changes here
}, null) //as the worker thread cannot access the UI thread resources
I'm learning about threads in C#, and i get this behavior that i cant understand.
The code simulates I/O operations, like files or serial port, where only one thread can access it at time, and it blocks until finishes.
Four threads are started. Each performs just a count. It works ok, i can see on the form the counts growing. But there is a button to count from the form thread. When i push it, the main thread freezes. The debugger shows that the others threads keep counting, one by one, but the form thread never gets access to the resource.
1) Why the lock(tty) from the form thread never gets access to it, when the others threads has no problem ?
2) Is there a better way to do this type of synchronization ?
Sorry about the big code:
public class MegaAPI
{
public int SomeStupidBlockingFunction(int c)
{
Thread.Sleep(800);
return ++c;
}
}
class UIThread
{
public delegate void dlComandoMaquina();
public class T0_SyncEvents
{
private EventWaitHandle _EventFechar; // Exit thread event
public T0_SyncEvents()
{
_EventFechar = new ManualResetEvent(false);
}
public EventWaitHandle EventFecharThread // Exit thread event
{
get { return _EventFechar; }
}
}
public class T0_Thread
{
private T0_SyncEvents _syncEvents;
private int _msTimeOut;
private dlComandoMaquina _ComandoMaquina;
public T0_Thread(T0_SyncEvents e, dlComandoMaquina ComandoMaquina, int msTimeOut)
{
_syncEvents = e;
_msTimeOut = msTimeOut;
_ComandoMaquina = ComandoMaquina;
}
public void VaiRodar() // thread running code
{
while (!_syncEvents.EventFecharThread.WaitOne(_msTimeOut, false))
{
_ComandoMaquina();
}
}
}
}
public partial class Form1 : Form
{
MegaAPI tty;
UIThread.T0_Thread thr1;
UIThread.T0_SyncEvents thrE1;
Thread Thread1;
int ACount1 = 0;
void UIUpdate1()
{
lock (tty)
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
}
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
UIThread.T0_Thread thr2;
UIThread.T0_SyncEvents thrE2;
Thread Thread2;
int ACount2 = 0;
void UIUpdate2()
{
lock (tty)
{
ACount2 = tty.SomeStupidBlockingFunction(ACount2);
}
this.BeginInvoke((Action)delegate { txtAuto2.Text = ACount2.ToString(); });
}
UIThread.T0_Thread thr3;
UIThread.T0_SyncEvents thrE3;
Thread Thread3;
int ACount3 = 0;
void UIUpdate3()
{
lock (tty)
{
ACount3 = tty.SomeStupidBlockingFunction(ACount3);
}
this.BeginInvoke((Action)delegate { txtAuto3.Text = ACount3.ToString(); });
}
UIThread.T0_Thread thr4;
UIThread.T0_SyncEvents thrE4;
Thread Thread4;
int ACount4 = 0;
void UIUpdate4()
{
lock (tty)
{
ACount4 = tty.SomeStupidBlockingFunction(ACount4);
}
this.BeginInvoke((Action)delegate { txtAuto4.Text = ACount4.ToString(); });
}
public Form1()
{
InitializeComponent();
tty = new MegaAPI();
thrE1 = new UIThread.T0_SyncEvents();
thr1 = new UIThread.T0_Thread(thrE1, UIUpdate1, 500);
Thread1 = new Thread(thr1.VaiRodar);
Thread1.Start();
thrE2 = new UIThread.T0_SyncEvents();
thr2 = new UIThread.T0_Thread(thrE2, UIUpdate2, 500);
Thread2 = new Thread(thr2.VaiRodar);
Thread2.Start();
thrE3 = new UIThread.T0_SyncEvents();
thr3 = new UIThread.T0_Thread(thrE3, UIUpdate3, 500);
Thread3 = new Thread(thr3.VaiRodar);
Thread3.Start();
thrE4 = new UIThread.T0_SyncEvents();
thr4 = new UIThread.T0_Thread(thrE4, UIUpdate4, 500);
Thread4 = new Thread(thr4.VaiRodar);
Thread4.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
thrE1.EventFecharThread.Set();
thrE2.EventFecharThread.Set();
thrE3.EventFecharThread.Set();
thrE4.EventFecharThread.Set();
Thread1.Join();
Thread2.Join();
Thread3.Join();
Thread4.Join();
}
int Mcount = 0;
private void btManual_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
lock (tty) // locks here ! Never runs inside! But the other threads keep counting..
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
txtManual.Text = Mcount.ToString();
}
Cursor.Current = Cursors.Default;
}
}
I suspect you are hitting something with the Windows message loop and threading in WinForms. I don't know what that is, but here are a few pointers:
You can run the button's task in a backgroundWorker to keep the work off the UI thread. That solves the lock problem. Drag a BackgroundWorker from the toolbox and drop it on your Form in the designer, and hook up the event, i.e.:
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
then switch your code in btManual_Click to call the background worker like this:
backgroundWorker1.RunWorkerAsync();
and then:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
this.BeginInvoke((Action)delegate { txtManual.Text = Mcount.ToString(); });
}
I've left out the lock (tty) because I would rather see only one of these statements inside the function, rather than five of them outside. And instead of locking on tty, I would create a private variable like this:
public class MegaAPI
{
private object sync = new object();
public int SomeStupidBlockingFunction(int c)
{
lock (this.sync)
{
Thread.Sleep(800);
return ++c;
}
}
}
Everywhere else is then simplified, for example:
void UIUpdate1()
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
And since you can't run the background worker while it's still processing, here is a quick-and-dirty solution: disable the button while it's working:
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
and then:
private void btManual_Click(object sender, EventArgs e)
{
this.btManual.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
and:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.btManual.Enabled = true;
}
So I recommend:
Keep a single lock () statement
inside the function needing the
synchronization
Keep the lock object private
Run the work on a background worker
Mutexes do not provide fairness by default. They just guarantee that your process as a whole will make forward progress. It is the implementation's job to pick the best thread to get the mutex based on characteristics of the scheduler and so on. It is the coder's job to make sure that the thread that gets the mutex does whatever work the program needs done.
If it's a problem for you if the "wrong thread" gets the mutex, you are doing it wrong. Mutexes are for cases where there is no "wrong thread". If you need fairness or predictable scheduling, you need to use a locking primitive that provides it or use thread priorities.
Mutexes tend to act in strange ways when threads that hold them aren't CPU-limited. Your threads acquire the mutex and then deschedule themselves. This will lead to degenerate scheduling behavior just like the behavior you're seeing. (They won't break their guarantees, of course, but they will act much less like a theoretically perfect mutex that also provided things like fairness.)
I implemented threading in my application for scraping websites. After all the sites are scraped I want to process them.
form creates queueworker(which creates 2 workers and processes tasks).
After all the tasks are done I want to process them baack in the formthread.
At this point I accieved this with
public void WaitForCompletion()
{
// Enqueue one null task per worker to make each exit.
StopWorkers();
//wait for the workers to finish
foreach (Thread worker in workers)
{
worker.Join();
}
}
After a task is preformed I fire (from queueworker):
public event EventHandler<ProgressEvent> UrlScanned;
if (UrlScanned != null)
{
UrlScanned(this, new ProgressEvent(task.Name, 1));
}
And catch that event with:
urlscanner.UrlScanned += new EventHandler<ProgressEvent>(UrlScanningProgress);
private void UrlScanningProgress(object sender, ProgressEvent args)
{
if (pbarurlScan.InvokeRequired)
{
//don't use invoke when Thread.Join() is used! Deadlock
Invoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args);
//BeginInvoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args)};
}
else
{
pbarurlScan.Value++;
}
}
The problem is that the formthread gets blocked and with calling Invoke the whole application is now in a deadlock situation.
How can I give update to the formthread without having a deadlock and have an immidiate update (begininvoke occurs if the workers threads are done)
Why are you doing the Join? I would raise a callback at the end of each thread - perhaps decrementing a counter. When the counter gets to 0, then call back to the UI thread and do the "all done" code; something like:
using System.Windows.Forms;
using System.Threading;
using System;
class MyForm : Form
{
public MyForm()
{
Button btn = new Button();
Controls.Add(btn);
btn.Text = "Go";
btn.Click += btn_Click;
}
int counter;
void btn_Click(object sender, System.EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Interlocked.Increment(ref counter);
ThreadPool.QueueUserWorkItem(DoWork, i);
}
}
void DoWork(object state)
{
for (int i = 0; i < 10; i++)
{ // send progress
BeginInvoke((Action)delegate { Text += state.ToString(); });
Thread.Sleep(500);
}
EndThread(); // this thread done
}
void EndThread()
{
if (Interlocked.Decrement(ref counter) == 0)
{
AllDone();
}
}
void AllDone()
{
Invoke((Action)delegate { this.Text += " all done!"; });
}
[STAThread]
static void Main()
{
Application.Run(new MyForm());
}
}
I fire a seperate event now when all tasks are done. I moved the logic for processing the tasks to a seperate function that will be called when receiving the AllUrlsScanned event.