Replacing a While loop with AutoResetEvent for blocking a thread - c#

Recently, I was finally able to make a separate thread work. Now I am trying to master synchronization.
As far as I know, pausing a thread with ThreadName.Suspend() is not a good idea. At fist I used a While loop to block the thread. Later I noticed that this consumes resources, so now I am trying to replace the loop with an AutoResetEvent.
Here is some code (tell me if you the full code):
private void combTester(object sender, EventArgs e)//happens in a timer, because it manipulates the GUI
{
if (!timer2Block)
{
//stuff happens
genBlock = false;//unblocks the thread
timer2Block = true;//blocks itself
//debugging stuff happens
}
if (done)
timer2.Enabled = false;
}
private void combGenerator(int currEl, int begVal)
{
//setting a variable
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
while (genBlock && !abortTime)
{
if (abortTime)
return;
}
genBlock = true;//blocks itself
//some recursive stuff happens,
//because of which I was forced to use a thread instead of timers
}
}
I tried different places to put the Wait() and Set() methods, but both the tread and the timer get blocked and I don't know how to debug the program.
So, how can I replace the While loop with AutoResetEvent?

If what you want is to have a "pause" control for the worker thread then you should use a ManualResetEvent: keep the event signaled, and reset it when you want the thread to pause:
private void combGenerator(int currEl, int begVal)
{
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
manualResetEvent.WaitOne();
// do stuff
}
}
You can now pause/unpause the combGenerator thread by doing manualResetEvent.Reset() and manualResetEvent.Set() correspondingly.
This can be further expanded to include an "abort" signal by throwing in another ManualResetEvent (this could also be an AutoResetEvent, but as it's only going to do something once the distinction is not important):
var events = new[] { abortEvent, pauseEvent }; // order MATTERS!
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
var index = WaitHandle.WaitAny(events);
if (index == 0) {
// abort!
}
// do stuff
}
The magic here happens inside WaitAny. This method will wait for any of the events to become signaled and return the smallest index among the events that were signaled, if more than one. This is extremely important, as it will allow us to determine if we should abort.
During normal operation abortEvent will not be signaled and pauseEvent will be, so WaitAny will immediately return 1. If pauseEvent is reset then WaitAny will block until one of the events is again signaled. And if abortEvent is signaled then WaitAny will return 0, which is the cue to exit.

You can use another flag that checks whether it is recursive call or not, based on which you can decide to continue, or wait.
Example:
static int recCount = 0;
private void combGenerator(int currEl, int begVal)
{
//setting a variable
for (int c = begVal; c <= currEl + totalCells - maxCells; c++)
{
while (genBlock && !abortTime and recCount < 1)
{
if (abortTime)
return;
}
genBlock = true;//blocks itself
recCount ++;
//some recursive stuff happens,
//because of which I was forced to use a thread instead of timers
//after all the stuff is done
recCount--;
}
}

Related

Cross-thread operation not valid: Control 'lbDatabase' accessed from a thread other than the thread it was created on

I'm working on a fingerprint and I need to make this operation and I get an error, and don't know how to fix it
private void doVerify(object sender, DoWorkEventArgs args)
{
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < lbDatabase.Items.Count || verificationResult.score > 0; i++)
{
lbDatabase.Invoke(new MethodInvoker(delegate { lbDatabase.SelectedItem = i; }));
verificationResult.score = _engine.Verify(((CData)lbDatabase.SelectedItem).EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}
Error: Cross-thread operation not valid: Control 'lbDatabase' accessed
from a thread other than the thread it was created on
You have three places in your code where you access lbDatabase.
The loop - lbDatabase.Items.Count
Setting the selected item - lbDatabase.SelectedItem = i
Retrieving the selected item - lbDatabase.SelectedItem
I assume on the second one you meant to write lbDatabase.SelectedIndex = i.
Only the second one you are invoking. So the other two are running on the background worker thread. That's why you're getting the error.
All access to UI elements - reading and writing - needs to be done on the UI thread.
Now, since you're trying to do this using a background worker you have a method that will freeze up the UI if it solely ran on the UI thread. So you need the parts that access the control to run on the UI, but everything else to run on the background thread.
The next problem is though, that calling lbDatabase.Invoke(new MethodInvoker(delegate { lbDatabase.SelectedItem = i; })); pushes the instruction to the UI, but there is no guarantee that the code will immediately run - in fact the entire loop might run and queue up all of the invokes. You obviously want it to happen synchronously, but that wont happen.
Looking at your code you clearly only want to access all of the CData items on the lbDatabase list box. There's a very easy way to make this work.
Just try this when calling the background worker:
backgroundWorker1.RunWorkerAsync(lbDatabase.Items.Cast<CData>().ToArray());
And then change your doVerify to this:
private void doVerify(object sender, DoWorkEventArgs args)
{
CData[] items = (CData[])args.Argument;
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < items.Length || verificationResult.score > 0; i++)
{
verificationResult.score = _engine.Verify(items[i].EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}
The error is pretty self explantory. You're running on a different thread, so you can't interact with the control. This means accessing lbDatabase.Items.Count is out.
If instead you:
lbDatabase.Invoke((MethodInvoker)(() => {
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < lbDatabase.Items.Count || verificationResult.score > 0; i++)
{
lbDatabase.SelectedItem = i;
verificationResult.score = _engine.Verify(((CData)lbDatabase.SelectedItem).EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}));
then you'd probably be back in business. Now all of the accesses to the control are queued to run on the UI thread (and you're no longer switching contexts with Invoke in the middle of a loop... costly).

C#: Synchronizing threads in a particular order [duplicate]

I have three threads and some part of the code can run in parallel, some parts are locked(only one thread at the time). However one lock needs to only let them in in order. Since this is a loop it gets more complex. How do I make this behavior?
If i had a print statement I would like to receive the following output:
1,2,3,1,2,3,1,2,3.... currently I receive 2,3,1,3,1,3,2,1,2 A.K.A. random order.
The code which is executed in three threads in parallel:
while (true){
lock (fetchLock){
if(done){
break;
}
//Do stuff one at the time
}
//Do stuff in parralell
lock (displayLock){
//Do stuff one at the time but need's to be in order.
}
}
You could use a combination of Barrier and AutoResetEvent to achieve this.
Firstly, you use Barrier.SignalAndWait() to ensure that all the threads reach a common point before proceeding. This common point is the point at which you want the threads to execute some code in order.
Then you use numberOfThreads-1 AutoResetEvents to synchronise the threads. The first thread doesn't need to wait for any other thread, but after it has finished it should signal the event that the next thread is waiting on.
The middle thread (or threads if more than 3 threads total) needs to wait for the previous thread to signal the event that tells it to proceed. After it has finished, the middle thread should signal the event that the next thread is waiting on.
The last thread needs to wait for the previous thread to signal the event that tells it to proceed. Since it is the last thread, it does not need to signal an event to tell the next thread to proceed.
Finally, you resync the threads with another call to Barrier.SignalAndWait().
This is easiest to show via a sample console app. If you run it, you'll see that the work that should be done by the threads in order (prefixed with the letter "B" in the output) is indeed always in order, while the other work (prefixed with the letter "A") is executed in a random order.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
public static class Program
{
public static void Main()
{
using (Barrier barrier = new Barrier(3))
using (AutoResetEvent t2 = new AutoResetEvent(false))
using (AutoResetEvent t3 = new AutoResetEvent(false))
{
Parallel.Invoke
(
() => worker(1, barrier, null, t2),
() => worker(2, barrier, t2, t3),
() => worker(3, barrier, t3, null)
);
}
}
private static void worker(int threadId, Barrier barrier, AutoResetEvent thisThreadEvent, AutoResetEvent nextThreadEvent)
{
Random rng = new Random(threadId);
for (int i = 0; i < 1000; ++i)
{
doSomething(threadId, rng); // We don't care what order threads execute this code.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
if (thisThreadEvent != null) // If this thread is supposed to wait for a signal
thisThreadEvent.WaitOne(); // before proceeding, then wait for it.
doWorkThatMustBeDoneInThreadOrder(threadId);
if (nextThreadEvent != null) // If this thread is supposed to raise a signal to indicate
nextThreadEvent.Set(); // that the next thread should proceed, then raise it.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
}
}
private static void doWorkThatMustBeDoneInThreadOrder(int threadId)
{
Console.WriteLine(" B" + threadId);
Thread.Sleep(200); // Simulate work.
}
private static void doSomething(int threadId, Random rng)
{
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(rng.Next(50)); // Simulate indeterminate amount of work.
Console.WriteLine("A" + threadId);
}
}
}
}

Issue with thread barrier - PulseAll not reaching all threads

I have a parallel algorithm which I have some barrier issues with. Before y'all scream "search" I can say I have looked at available posts and links, and I have followed the instructions for a barrier with Monitor.Wait and Monitor.PulseAll, but my issue is that all threads except the last one created (and initiated) is reached by the PulseAll from my main thread. Here are how the basic layout of the code is:
public static object signal = new object(); //This one is located as class variable, not in the method
public void RunAlgorithm(List<City> cities){
List<Thread> localThreads = new List<Thread>();
object[] temp = //some parameters here
for(int i = 0; i < numOfCitiesToCheck; i++){
Thread newThread = new Thread((o) => DoWork(o as object[]));
newThread.IsBackground = true;
newThread.Priority = ThreadPriority.AboveNormal;
newThread.Start(temp as object);
localThreads.Add(newThread);
}
//All threads initiated, now we pulse all
lock(signal){
Monitor.PulseAll(signal);
}
int counter = 0;
while(true){
if(counter == localThreads.Count){ break; }
localThreads[counter].Join();
counter++;
}
}
That's what done by the main thread (removed a few uneccessary pieces) and as stated before the main thread will always get stuck in the Join() on the last thread in the list.
This is how the method of the threads look like:
private void DoWork(object[] arguments){
lock(signal){
Monitor.Wait(signal);
}
GoDoWork(arguments);
}
Are there any other barriers I can use for this type of signaling? All I want is to let the main thread signal all threads at the same time so that they start at the same time. I want them to start at the same time inorder to have as close parallel as possible (I measure running time for the algorithm and a few other things). Is there any part of my barrier or code that is flawed (with the barrier I mean)? I tried running an instance with fewer threads and it still get stuck on the last one, I don't know why it is. I have confirmed by via VS debug that the last thread is sleeping (all other threads are !isAlive, while the last one isAlive = true).
Any help appreciated!
I managed to solve it using the Barrier class. Many thanks to Damien_The_Unbeliever! Still can't believe I haven't heard of it before.
public Barrier barrier = new barrier(1);
public void RunAlgorithm(List<City> cities){
List<Thread> localThreads = new List<Thread>();
object[] temp = //some parameters here
for(int i = 0; i < numOfCitiesToCheck; i++){
barrier.AddParticipant();
Thread newThread = new Thread((o) => DoWork(o as object[]));
newThread.IsBackground = true;
newThread.Priority = ThreadPriority.AboveNormal;
newThread.Start(temp as object);
localThreads.Add(newThread);
}
barrier.SignalAndWait();
int counter = 0;
while(true){
if(counter == localThreads.Count){ break; }
localThreads[counter].Join();
counter++;
}
}
private void DoWork(object[] arguments){
barrier.SignalAndWait();
GoDoWork(arguments);
}

Cancel request if taking to long to process

Hello is this possible in c#:
If I have a loop say:
int x = 0;
for (int i = 0; i < 1000000; i++) {
x++;
}
And it takes more than 1 second to complete, is it possible to kill the code and move on?
Yes, if you have the loop running in a different thread, you can abort that thread from a different thread. This would effectively kill the code you're running, and would work fine in the simplified example you've given. The following code demonstrates how you might do this:
void Main()
{
double foo = 0;
var thread = new Thread(() => foo = GetFoo());
thread.Start();
string message;
if(thread.Join(1000))
{
message = foo.ToString();
}
else
{
message = "Process took too long";
thread.Abort();
}
message.Dump();
}
public double GetFoo() {
double a = RandomProvider.Next(2, 5);
while (a == 3) { RandomProvider.Next(2, 5);}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9) { RandomProvider.Next(8,11); }
double f = b / e;
return f;
}
However, as you can see from Eric Lippert's comment (and others), aborting a thread is not very graceful (a.k.a. "pure evil"). If you were to have important things happening inside this loop, you could end up with data in an unstable state by forcing the thread abortion in the middle of the loop. So it is possible, but whether you want to use this approach will depend on what exactly you're doing in the loop.
So a better option would be to have your loops voluntarily decide to exit when they're told to (Updated 2015/11/5 to use newer TPL classes):
async void Main()
{
try
{
var cancelTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000));
var foo = await GetFooAsync(cancelTokenSource.Token);
Console.WriteLine(foo);
}
catch (OperationCanceledException e)
{
Console.WriteLine("Process took too long");
}
}
private Random RandomProvider = new Random();
public async Task<double> GetFooAsync(CancellationToken cancelToken) {
double a = RandomProvider.Next(2, 5);
while (a == 3)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(2, 5);
}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(8,11);
}
double f = b / e;
return f;
}
This gives GetFooAsync an opportunity to catch on to the fact that it's supposed to exit soon, and make sure it gets into a stable state before giving up the ghost.
If you control the code that needs to be shut down then write logic into it that enables it to be shut down cleanly from another thread.
If you do not control the code that needs to be shut down then there are two scenarios. First, it is hostile to you and actively resisting your attempts to shut it down. That is a bad situation to be in. Ideally you should run that code in another process, not another thread, and destroy the process. A hostile thread has lots of tricks it can do to keep you from shutting it down.
Second, if it is not hostile and it can't be shut down cleanly then either it is badly designed, or it is buggy. Fix it. If you can't fix it, run it in another process, just like it was hostile.
The last thing you should do is abort the thread. Thread aborts are pure evil and should only be done as a last resort. The right thing to do is to design the code so that it can be cancelled cleanly and quickly.
More thoughts:
http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx
Alternatively, you could go with a single-threaded approach. Break the work up into small chunks where the last thing each chunk of work does is enqueues the next chunk of work onto a work queue. You then sit in a loop, pulling work out of the queue and executing it. To stop early, just clear the queue. No need to go with a multithreaded approach if you don't need to.
You can achieve this in a simple way without mucking around with threading:
int x = 0;
int startTime = Environment.TickCount;
for (int i = 0; i < 1000000; i++)
{
x++;
int currentTime = Environment.TickCount;
if ((currentTime - startTime) > 1000)
{
break;
}
}
You can replace Environment.TickCount with a DateTime call or System.Diagnostics.Stopwatch if you like.
You can use background worker, this class supports cancellation
If the problem is the number of iteration in the loop more than what you do inside the loop, then you can ask for save the time when the loop started, and see de diference betweeen each iteration ( or maybe %10, 20, 100) and cancel if the time you wanted to spend on that task is over.

Race condition during thread start?

I'm running the following code to start my threads, but they don't start as intended. For some reason, some of the threads start with the same objects (and some don't even start). If I try to debug, they start just fine (extra delay added by me clicking F10 to step through the code).
These are the functions in my forms app:
private void startWorkerThreads()
{
int numThreads = config.getAllItems().Count;
int i = 0;
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var t = new Thread(() => WorkerThread(tmpItem, i));
t.Start();
//return t;
}
}
private void WorkerThread(ConfigurationItem cfgItem, int mul)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(10*mul);
}
this.Invoke((ThreadStart)delegate()
{
this.textBox1.Text += "Thread " + cfgItem.name + " Complete!\r\n";
this.textBox1.SelectionStart = textBox1.Text.Length;
this.textBox1.ScrollToCaret();
});
}
Anyone able to help me out?
Starting a thread doesn't really start the thread. Instead it schedules it for execution. I.e. at some point it will get to run when it is scheduled. Scheduling threads is a complex topic and an implementation detail of the OS, so your code should not expect a certain scheduling.
You're also capturing variables in your lambda. Please see this post (there is a section on Captured Variables) for the problems associated with doing that.
You just run into the (be me called) lambda error.
You provide the ConfigurationItem from the foreach loop directly. This leads to the fact, that all your threads get the same item (the last one).
To get this to work you have to create a reference for each item and apply this to each thread:
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var currentI = i;
var currentItem = tmpItem;
var t = new Thread(() => WorkerThread(currentItem, currentI));
t.Start();
//return t;
}
And you should also consider using a ThreadPool.
MSDN Description about how to use the ThreadPool
Short summary of differences here on SO
The problem seems to be there : () => WorkerThread(tmpItem, i)
I'm not used to Func<> but it seems to work like anonymous delegates in .NET 2.0. Thus, you may have a reference to the arguments of the WorkerThread() method. Hence, their values are retrieved later (when the thread actually runs).
In this case, you may already be at the next iteration of your main thread...
Try this instead :
var t = new Thread(new ParametrizedThreadStart(WorkerThread));
t.Start(new { ConfigurationItem = tmpItem, Index = i } );
[EDIT] Other implementation. More flexible if you need to pass new parameters to the thread in the future.
private void startWorkerThreads()
{
int numThreads = config.getAllItems().Count;
int i = 0;
foreach (ConfigurationItem tmpItem in config.getAllItems())
{
i++;
var wt = new WorkerThread(tmpItem, i);
wt.Start();
//return t;
}
}
private class WorkerThread
{
private ConfigurationItem _cfgItem;
private int _mul;
private Thread _thread;
public WorkerThread(ConfigurationItem cfgItem, int mul) {
_cfgItem = cfgItem;
_mul = mul;
}
public void Start()
{
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(10 * _mul);
}
this.Invoke((ThreadStart)delegate()
{
this.textBox1.Text += "Thread " + _cfgItem.name + " Complete!\r\n";
this.textBox1.SelectionStart = textBox1.Text.Length;
this.textBox1.ScrollToCaret();
});
}
}
Do you really need to spawn threads manually (which is a rather expensive task) ? You could try to switch to the ThreadPool instead.
You can't assume that the threads will run in the same order they were called, unless you force it, and cause a dependency between them.
So the real question is - what is your goal ?
I think that the error is somewhere else. Here are some hints to help you debug :
Give a name containing to each thread, and display the thread name instead of the config item name :
this.textBox1.Text += "Thread " + Thread.Current.Name + " Complete!\r\n";
Display the content of config.getAllItems(), may be that some items has the same name (duplicated)
===========
Here are some additional information about multi threading with winforms:
dont create new Thread directly, use the ThreadPool instead :
ThreadPool.QueueUserWorkItem(state => { WorkerThread(tmpItem, i); });
If you really want to creat your threads, use this.BeginInvoke instead of this.Invoke your worker thread will finish sooner => less concurrent thread => better global performance
don't call Thread.Sleep in a loop, just do a big sleep: Thread.Sleep(10*mul*100);
I hope that this will help you.
Thanks to all of you!
I just implemented the threadpool, and that worked like a charm - with the added bonus of not spawning too many threads at once.
I'll have a look at the other solutions, too, but this time around the threadpool will save me from having to manually check for bozos with too many configs ;)

Categories

Resources