Multithreading and how to make sure that everything is perfectly synchronized - c#

So first all of my example code:
class Program
{
static List<string> queue = new List<string>();
static System.Threading.Thread queueWorkerThread;
static void Main(string[] args)
{
// Randomly call 'AddItemToQueue' at certain circumstances and user inputs (unpredictable)
}
static void AddItemToQueue(string item)
{
queue.Add(item);
// Check if the queue worker thread is active
if (queueWorkerThread == null || queueWorkerThread.IsAlive == false)
{
queueWorkerThread = new System.Threading.Thread(QueueWorker);
queueWorkerThread.Start();
Console.WriteLine("Added item to queue and started queue worker!");
}
else
{
Console.WriteLine("Added item to queue and queue worker is already active!");
}
}
static void QueueWorker()
{
do
{
string currentItem = queue[0];
// ...
// Do things with 'currentItem'
// ...
// Remove item from queue and process next one
queue.RemoveAt(0);
} while (queue.Count > 0);
// Reference Point (in my question) <----
}
}
What I am trying to create in my code is a QueueWorker()-method which is always active when there is something in the queue.
Items can be added to the queue via a AddItemToQueue()-method as you can see in the code example.
It basically adds the item to the queue and then checks whether the queue worker is active (aka. if there were other items in the queue previously) or if its not (aka. if the queue was completely empty previously).
And what I am not fully sure about is that: Let's say the queue-worker-thread was currently at the position shown in the screenshot (it left the while-loop just now) and of course the thread's IsAlive-property is still set to true at this point.
So what if the AddItemToQueue()-method checked the thread's IsAlive-property at the exact same time?
That would mean the thread would end shortly after and the new item would just be left in the queue and nothing would happen because the AddItemToQueue()-method didn't realize that the thread was just about to end.
How do I deal with this? (I want to make sure everything works 100%)
(If there's any questions about my question or something is not clear, then feel free to ask!)

Related

C# Wait until the object has been inserted to the list (freeze application)

I have stumbled upon an annoying problem. I have a timer that foreach a list(Generics) every 250ms (1-5 objects in the list). And if it "meets" the criteria, it should add the object to an "ignore list". But the problem is that sometimes it doesn't add the object to the ignore list and therefore letting it through (even if it 250ms ago should have added it).
So my question is, what the best way to make sure that the loop freezes until the object has been added to the list (Now everything is running on the main thread)?
// this method is called every 250ms
void check()
{
foreach (GetAll g in GetAllInList)
{
InIgnoreList(g);
}
}
// InIgnoreList(g)
void InIgnoreList(g)
{
foreach(var b in g.List())
{
if(IgnoreList.Exists(x => x.Name == g.Name))
break;
// New method where I add it, but sometimes the IgnoreList.Exists Check lets it
through
}
}
Thanks :)
It sounds like you're encountering a race condition - it may be that check() is being called before the last call to check() has actually finished.
If you do something like this it would eliminate the race condition...
readonly object lockObject = new Object();
void check()
{
lock (lockObject)
{
foreach (GetAll g in GetAllInList)
{
InIgnoreList(g);
}
}
}
Alternatively, you could use lock in combination with a bool flag to determine if the check() method is still running before calling it when the timer event fires.
Disable the timer before calling your check() code (or at the beginning of check(), as it's not clear what the context is here), and enable it when check() returns (or at the end of check()). This stops the timer from being fired again before the code completes.

Execute the last thread of ThreadPool only

I am creating an auto-complete control that updates as the user types text. Every time the user types a key a new thread fires in order to filter the results. The results come over the network and are a lot therefore it takes about 1 minute to filter. This is something similar of what I have:
object _lock = new object();
volatile static bool isThreadRunning=false ;
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
var text = textBox1.Text.ToUpper();
ThreadPool.QueueUserWorkItem((o) =>
{
lock (_lock) // avoid multiple threads to be running at the same time
{
isThreadRunning = true;
// do work in here
isThreadRunning=false;
}
},text);
}
So as you can see if I where to quickly type "Hello" then 5 threads will be created and 4 of them will have to wait for the first one to finish. Once that thread finishes the next one will continue to execute and so on.
If there exists 4 threads waiting to execute I will like to only execute the last one. Also the threads enter the lock in random order. How could I determine which is the last one. If a new thread fires and a thread is currently executing maybe I could cancel that thread somehow and that way the order will always be correct. How can I implement that algorithm?
EDIT
This is what I have worked out:
class DoWorkOnce
{
static object _lock = new object();
static Stack<Action> Work = new Stack<Action>();
public static void Add(Action task)
{
Work.Push(task);
DoSomeWork();
}
private static void DoSomeWork()
{
Task.Factory.StartNew(() =>
{
lock (_lock) // ensure that the following block of code is only executed at once
{
if (Work.Count == 0) // if there is no items in the stack return
return;
Work.Pop()(); // get the last item in the stack and execute it
// remove the bottom of the stack by poping everything exept the top item
Action temp=null;
if(Work.Count>0)
temp = Work.Pop();
while (Work.Count > 0)
Work.Pop();
if (temp != null)
Work.Push(temp);
}
});
}
}
and I can use that class as:
string[] simulationOfTyping = new string[] { "H", "He", "Hel", "Hell", "Hello", "Hello ", "Hello W", "Hello Wo", "Hello Wor", "Hello Worl", "Hello World" };
// simulate user typing
foreach(var text in simulationOfTyping)
{
Thread.Sleep(50);
DoWorkOnce.Add(() =>
{
Console.WriteLine(text);
Thread.Sleep(1000);
});
}
// the last item should execute always.
Aside from mellamokb's comment, it sounds like you don't really want a thread pool at all - you want a single thread, with a single "next task to execute" - where if there's already a task to execute, it's overwritten by the new one. Essentially like a producer/consumer queue, but with only one "slot" which is overwritten.
In TPL Dataflow, this is exactly what BroadcastBlock does: it will always remember only the last item posted to it. If you link it to an ActionBlock with capacity bounded to 1, that ActionBlock's action will execute the way you want.
Although it probably doesn't make much sense to use TPL Dataflow just for this.

Implementing a blocking queue in C#

I've use the below code to implement and test a blocking queue. I test the queue by starting up 5 concurrent threads (the removers) to pull items off the queue, blocking if the queue is empty and 1 concurrent thread (the adder) to add items to the queue intermitently. However, if I leave it running for long enough I get an exception because one of the remover threads comes out of a waiting state even when the queue is empty.
Does anyone know why I get the exception? Note, I'm interested in knowing why this doesn't work as opposed to a working solution (as I can just Google that).
I'd greatly appreciate your help.
using System;
using System.Threading;
using System.Collections.Generic;
namespace Code
{
class Queue<T>
{
private List<T> q = new List<T>();
public void Add(T item)
{
lock (q)
{
q.Add(item);
if (q.Count == 1)
{
Monitor.Pulse(q);
}
}
}
public T Remove()
{
lock (q)
{
if (q.Count == 0)
{
Monitor.Wait(q);
}
T item = q[q.Count - 1];
q.RemoveAt(q.Count - 1);
return item;
}
}
}
class Program
{
static Random r = new Random();
static Queue<int> q = new Queue<int>();
static int count = 1;
static void Adder()
{
while (true)
{
Thread.Sleep(1000 * ((r.Next() % 5) + 1));
Console.WriteLine("Will try to add");
q.Add(count++);
}
}
static void Remover()
{
while (true)
{
Thread.Sleep(1000 * ((r.Next() % 5) + 1));
Console.WriteLine("Will try to remove");
int item = q.Remove();
Console.WriteLine("Removed " + item);
}
}
static void Main(string[] args)
{
Console.WriteLine("Test");
for (int i = 0; i < 5; i++)
{
Thread remover = new Thread(Remover);
remover.Start();
}
Thread adder = new Thread(Adder);
adder.Start();
}
}
}
if I leave it running for long enough I get an exception because one of the remover threads comes out of a waiting state even when the queue is empty. Does anyone know why I get the exception?
The question is odd, because obviously you know the answer: your first sentence answers the question asked by the second sentence. You get the exception because a remover thread comes out of the wait state when the queue is empty.
To solve the problem you'll want to use a loop instead of an "if". The correct code is:
while(q.Count == 0) Monitor.Wait(q);
not
if(q.Count == 0) Monitor.Wait(q);
UPDATE:
A commenter points out that perhaps your question was intended to be "under what circumstances can a consumer thread obtain the monitor when the queue is empty?"
Well, you are in a better position to answer that than we are, since you're the one running the program and looking at the output. But just off the top of my head, here's a way that could happen:
Consumer Thread 1: waiting
Consumer Thread 2: ready
Producer Thread 3: owns the monitor
There is one element in the queue.
Thread 3 pulses.
Thread 1 goes to ready state.
Thread 3 abandons the monitor.
Thread 2 enters the monitor.
Thread 2 consumes the item in the queue
Thread 2 abandons the monitor.
Thread 1 enters the monitor.
And now thread 1 is in the monitor with an empty queue.
Generally speaking when reasoning about these sorts of problems you should think of "Pulse" as being like a pigeon with a note attached to it. Once released it has no connection to the sender, and if it cannot find its home, it dies in the wilderness with its message undelivered. All you know when you Pulse is that if there is any thread waiting then one thread will move to the ready state at some time in the future; you don't know anything else about the relative timing of operations on threads.
Your code would work if there was 1 consumer but when there are more, this mechanism fails and it should be while(q.Count == 0) Monitor.Wait(q)
The following scenario shows when if(q.Count == 0) Monitor.Wait(q) would fail (it's different than Eric's):
consumer 1 is waiting
producer has put in an item and is pulsing
consumer 1 is ready
producer is releasing lock
consumer 2 just entered Remove, is lucky and acquires lock
consumer 2 sees 1 item, does not wait and takes item out
consumer 2 releases lock
consumer 1 re-acquires lock but queue is empty
This happens exactly as documentation says it can happen:
When the thread that invoked Pulse releases the lock, the next thread in the ready queue (which is not necessarily the thread that was pulsed) acquires the lock.
Eric is of course right; the fact is that while the code appears to cover all the bases; the fact that an exception occurs shows that you haven't.
The race condition is that between the Monitor.Wait on a remover and a Monitor.Pulse on the adder (which releases the lock; but doesn't necessarily immediately trigger a thread waiting to wake up and reacquire it); a subsequent remove thread can acquire the lock and immediately jump the
if (q.Count == 0)
{
Monitor.Wait(q);
}
Statement and go straight to removing the item. Then, the Pulsed thread wakes up and assumes there's an item still there; but there isn't.
The way to fix it, whatever the way the race condition is actually manifesting, is as Eric has said.
Equally if you read the example on Monitor.Pulse you'll see a similar setup to what you have done here but a subtlely different way of doing it.

C# - how to implement an image preloading cache with threads

In my application, there is a list of images through which the user can step. Image loading is slow, so to improve user experience I would like to preload some images in the background (e.g. those images in the list succeeding the currently selected one).
I've never really used threads in C#, so I am looking for some kind of "best practice" advice how to implement the following behaviour:
public Image LoadCachedImage(string path)
{
// check if the cache (being operated in the background)
// has preloaded the image
Image result = TryGetFromCache(path);
if (result == null) { result = LoadSynchronously(path); }
// somehow get a list of images that should be preloaded,
// e.g. the successors in the list
string[] candidates = GetCandidates(path);
// trigger loading of "candidates" in the background, so they will
// be in the cache when queried later
EnqueueForPreloading(candidates);
return result;
}
I believe, a background thread should be monitoring the queue, and consecutively process the elements that are posted through EnqueueForPreloading(). I would like to know how to implement this "main loop" of the background worker thread (or maybe there is a better way to do this?)
If you really need sequential processing of the candidates, you can do one of the following:
Create a message queue data structure that has a AutoResetEvent. The class should spawn a thread that waits on the event and then processes everything in the queue. The class's Add or Enqueue should add it to the queue and then set the event. This would release the thread, which processes the items in the queue.
Create a class that starts an STA thread, creates a System.Windows.Forms.Control, and then enters Application.Run(). Every time you want to process an image asynchronously, call Control.BeginInvoke(...) and the STA thread will pick it up in its message queue.
There are probably other alternatives, but these two would be what I would try.
If you don't actually need sequential processing, consider using ThreadPool.QueueUserWorkItem(...). If there are free pool threads, it will use them, otherwise it will queue up the items. But you won't be guaranteed order of processing, and several may/will get processed concurrently.
Here's a (flawed) example of a message queue:
class MyBackgroundQueue<T>
{
private Queue<T> _queue = new Queue<T>();
private System.Threading.AutoResetEvent _event = new System.Threading.AutoResetEvent(false);
private System.Threading.Thread _thread;
public void Start()
{
_thread = new System.Threading.Thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
public class ItemEventArgs : EventArgs
{ public T Item { get; set; } }
public event EventHandler<ItemEventArgs> ProcessItem;
private void ProcessQueueWorker()
{
while (true)
{
_event.WaitOne();
while (_queue.Count > 0)
ProcessItem(this, new ItemEventArgs { Item = _queue.Dequeue() });
}
}
public void Enqueue(T item)
{
_queue.Enqueue(item);
_event.Set();
}
}
One flaw here, of course, are that _queue is not locked so you'll run into race conditions. But I'll leave it to you to fix that (e.g. use the 2 queue swap method). Also, the while(true) never breaks, but I hope the sample serves your purpose.
This is what I call cheat caching. The operating system already caches files for you, but you have to access them first. So what you can do is just load the files but don't save a reference to them.
You can do this without multi-threading per-se, and without holding the images in a list. Just create a method delegate and invoke for each file you want to load in the background.
For example, pre-loading all the jpeg images in a directory.
Action<string> d = (string file) => { System.Drawing.Image.FromFile(file); };
foreach(string file in dir.GetFiles("*.jpg"))
d.BeginInvoke(file);
BeginInvoke() is a multi-threaded approach to this, that loop will go very fast, but each file will be loaded on a different thread. Or you could change that up a little to put the loop inside the delegate, aka.
public void PreCache(List<string> files)
{
foreach(string file in files)
System.Drawing.Image.FromFile(file);
}
Then in your code
Action<List<string>> d = PreCache;
d.BeginInvoke(theList);
Then all the loading is done on just one worker thread.

Using Threads and .Invoke() and controls still remain inactive - C#

I am trying to populate a text box with some data, namely the names of several instruments a line at a time.
I have a class that will generate and return a list of instruments, I then iterate through the list and append a new line to the text box after each iteration.
Starting the Thread:
private void buttonListInstruments_Click(object sender, EventArgs e)
{
if (ins == null)
{
ins = new Thread(GetListOfInstruments);
ins.Start();
}
else if (ins != null)
{
textBoxLog.AppendText("Instruments still updating..");
}
}
Delegate to update textbox:
public delegate void UpdateLogWithInstrumentsCallback(List<Instrument> instruments);
private void UpdateInstruments(List<Instrument> instruments)
{
textBoxLog.AppendText("Listing available Instruments...\n");
foreach (var value in instruments)
{
textBoxLog.AppendText(value.ToString() + "\n");
}
textBoxLog.AppendText("End of list. \n");
ins = null;
}
Invoking the control:
private void GetListOfInstruments()
{
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
}
Note: GetInstruments() returns a List of type Instrument.
I am implementing therads to try to keep the GUI functional whilst the text box updates.
For some reason the other UI controls on the WinForm such as a seperate combo box remain inactive when pressed until the text box has finished updating.
Am I using threads correctly?
Thanks.
You haven't accomplished anything, the UpdateInstruments() method still runs on the UI thread, just like it did before. Not so sure why you see such a long delay, that must be a large number of instruments. You can possibly make it is less slow by first appending all of them into a StringBuilder, then append its ToString() value to the TextBox. That cuts out the fairly expensive Windows call.
I would recommend using a SynchronizationContext in general:
From the UI thread, e.g. initialization:
// make sure a SC is created automatically
Forms.WindowsFormsSynchronizationContext.AutoInstall = true;
// a control needs to exist prior to getting the SC for WinForms
// (any control will do)
var syncControl = new Forms.Control();
syncControl.CreateControl();
SyncrhonizationContext winformsContext = System.Threading.SynchronizationContext.Current;
Later on, from any thread wishing to post to the above SC:
// later on -- no need to worry about Invoke/BeginInvoke! Whoo!
// Post will run async and will guarantee a post to the UI message queue
// that is, this returns immediately
// it is OKAY to call this from the UI thread or a non-UI thread
winformsContext.Post(((state) => ..., someState);
As others have pointed out, either make the UI update action quicker (this is the better method!!!) or separate it into multiple actions posted to the UI queue (if you post into the queue then other message in the queue won't be blocked). Here is an example of "chunking" the operations into little bit of time until it's all done -- it assumes UpdateStuff is called after the data is collected and not necessarily suitable when the collection itself takes noticeable time. This doesn't take "stopping" into account and is sort of messy as it uses a closure instead of passing the state. Anyway, enjoy.
void UpdateStuff (List<string> _stuff) {
var stuff = new Queue<string>(_stuff); // make copy
SendOrPostCallback fn = null; // silly so we can access in closure
fn = (_state) => {
// this is in UI thread
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < 20 && stuff.Count > 0) {
var item = stuff.Dequeue();
// do stuff with item
}
if (stuff.Count > 0) {
// have more stuff. we may have run out of our "time-slice"
winformsContext.Post(fn, null);
}
};
winformsContext.Post(fn, null);
}
Happy coding.
Change this line:
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
with this:
textBoxLog.BeginInvoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
You are feeding all instruments into the textbox at once rather then one-by-one in terms of threading. The call to Invoke shall be placed in the for-loop and not to surround it.
nope, you start a thread, and then use invoke, which basically means you are going back to the UI thread to do the work... so your thread does nothing!
You might find that it's more efficient to build a string first and append to the textbox in one chunk, instead of line-by-line. The string concatenation operation could then be done on the helper thread as well.

Categories

Resources