Subscribe multiple threads to the same event signal to wake up - c#

I have a queue wrapper class which is storing items to a list, and multiple threads in the main program that are consuming these items until the list is empty. In this moment, the threads have to wait until the buffer will enqueue more items to the list.
I have an event fired every time that an item is enqueued, and I need to notify the threads that they have fresh items ready to consume.
public event EventHandler ItemEnqueued;
public void Enqueue(string item)
{
_itemsList.Add(item);
OnItemEnqueued();
}
void OnItemEnqueued()
{
ItemEnqueued?.Invoke(this, EventArgs.Empty);
}
How can I notify the threads of the main program that an item has been enqueued?
Many thanks!
EDIT to clarify
public class Queue
{
private readonly List<string> _itemsList = new List<string>();
public void Enqueue(String val)
{
_itemsList.Add(val);
OnItemEnqueued();
}
void OnItemEnqueued()
{
//here I have to tell the threads that a new item has been added
}
public string Dequeue()
{
//FIFO queue
if (_itemsList.Any())
{
var first = _itemsList.First();
_itemsList.RemoveAt(0);
return first;
}
return default(string);
}
public int Count()
{
return _itemsList.Count;
}
}
}
And I have to create two threads and make them "fight" for the enqueued items:
class Program
{
readonly object _syncLock = new object();
Queue _q = new Queue();
static void Main(string[] args)
{
Program p = new Program();
p.InitThreads();
}
public void InitThreads()
{
lock (_syncLock) //exclusively add items
{
for (var i = 0; i <= 99; i++)
{
_q.Enqueue(i.ToString());
}
}
Thread t1 = new Thread(() => {
while(_q.Count() > 0)
Console.WriteLine("T1 dequeued " + Consume());
});
Thread t2 = new Thread(() =>
{
while (_q.Count() > 0)
Console.WriteLine("T2 dequeued " + Consume());
});
t1.Start();
t2.Start();
//at some moment I have to tell the threads to wait until a new item has been enqueued
}
public string Consume()
{
lock (_syncLock) //safely get one item
{
return _q.Dequeue();
}
}
}

Not sure if this is what you're looking for, but here's a compliable code sample that demonstrates how to use AutoResetEvent to signal just one thread at once:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
static class Program
{
public static void Main()
{
var signal = new AutoResetEvent(initialState:false);
for (int i = 0; i < 4; ++i)
Task.Run(() => worker(signal));
while (true)
{
Console.WriteLine("Press <ENTER> to wake a thread.");
Console.ReadLine();
signal.Set();
}
}
static void worker(AutoResetEvent signal)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
while (true)
{
Console.WriteLine($"Thread {threadId} is waiting for a signal.");
signal.WaitOne();
Console.WriteLine($"Thread {threadId} received a signal");
}
}
}
}
The key thing to note is that you create a single AutoResetEvent and pass it to all the threads, which then wait on it. Then the "main" thread signals the event when it wants one of the threads to respond.
I wouldn't use a ManualResetEvent for this kind of thing, because then all the threads would be signalled simultaneously, which it looks like you want to avoid.

Related

c# multiple threads waiting for a ManualResetEvent

I'm messing around with multithreading and making some sort of task engine. The idea is that the engine can have a configurable amount of threads waiting and when a new task arrives the first free thread picks it up and executes it.
The problem is that something 2 threads pickup the same task somehow. I looked it through and I think that this code should work but obviously it doesn't. If I add the 10ms sleep where it is now commented out it works, but I'm not sure I understand why. It looks like the .Reset() function returns before it actually resets the event?
Can somebody explain? Is there a better way to let only a single thread continue when there are multiple waiting?
Thanks
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskTest
{
public class Engine
{
private ManualResetEvent taskEvent;
private ConcurrentQueue<Task> tasks;
private bool running;
private List<Thread> threads;
private int threadAmount;
private int threadsBusy = 0;
public Engine(int amountOfThreads)
{
taskEvent = new ManualResetEvent(false);
tasks = new ConcurrentQueue<Task>();
threads = new List<Thread>();
threadAmount = amountOfThreads;
}
public void Start()
{
running = true;
for (var i = 0; i < threadAmount; i++)
{
var thread = new Thread(Process);
thread.Name = "Thread " + i;
threads.Add(thread);
thread.Start();
}
}
public void Stop()
{
running = false;
taskEvent.Set();
threads.ForEach(t => t.Join());
}
private void Process()
{
while (running)
{
lock (taskEvent)
{
// Lock it so only a single thread is waiting on the event at the same time
taskEvent.WaitOne();
taskEvent.Reset();
//Thread.Sleep(10);
}
if (!running)
{
taskEvent.Set();
return;
}
threadsBusy += 1;
if (threadsBusy > 1)
Console.WriteLine("Failed");
Task task;
if (tasks.TryDequeue(out task))
task.Execute();
threadsBusy -= 1;
}
}
public void Enqueue(Task t)
{
tasks.Enqueue(t);
taskEvent.Set();
}
}
}
EDIT
Rest of the code:
namespace TaskTest
{
public class Start
{
public static void Main(params string[] args)
{
var engine = new Engine(4);
engine.Start();
while (true)
{
Console.Read();
engine.Enqueue(new Task());
}
}
}
}
namespace TaskTest
{
public class Task
{
public void Execute()
{
Console.WriteLine(Thread.CurrentThread.Name);
}
}
}
When using Console.Read() on a key press, two characters are read from the input. You should use Console.ReadLine() instead.
Note that your code can be simplified a lot by using a BlockingCollection to handle the synchronization:
public class Engine
{
private BlockingCollection<Task> tasks;
private List<Thread> threads;
private int threadAmount;
public Engine(int amountOfThreads)
{
tasks = new BlockingCollection<Task>();
threads = new List<Thread>();
threadAmount = amountOfThreads;
}
public void Start()
{
for (var i = 0; i < threadAmount; i++)
{
var thread = new Thread(Process);
thread.Name = "Thread " + i;
threads.Add(thread);
thread.Start();
}
}
public void Stop()
{
tasks.CompleteAdding();
threads.ForEach(t => t.Join());
}
private void Process()
{
foreach (var task in tasks.GetConsumingEnumerable())
{
task.Execute();
}
}
public void Enqueue(Task t)
{
tasks.Add(t);
}
}

C# multiple reusable worker threads

I am trying to build some kind of multi-thread game engine with reusable worker threads. That means the workers are running an endless loop and, after every iteration, call a method that suspends the thread with an AutoResetEvent until the next iteration is started from outside. Thet works fine.
But then I want to wait for all of the worker threads to get into the waiting state. But the last thread is always ignored in the first step.
This is my code:
class WorkerThread
{
private readonly Game game;
private readonly Task task;
private readonly AutoResetEvent waitEvent;
private readonly AutoResetEvent finishEvent;
public string Message { get; set; }
public bool Active { get; private set; }
public WorkerThread(Game game)
{
this.game = game;
waitEvent = new AutoResetEvent(false);
finishEvent = new AutoResetEvent(false);
task = new Task(startTask);
}
public void Start()
{
task.Start();
}
public void PerformFrame()
{
finishEvent.Reset();
waitEvent.Set();
}
public void WaitForFrameToFinish()
{
finishEvent.WaitOne();
}
private void startTask()
{
WaitFrame();
run();
}
long sum;
private void run()
{
while (true)
{
sum = 0;
for (int i = 0; i < 1000000; i++)
{
sum += i;
}
Console.WriteLine(Message);
WaitFrame();
}
}
private void WaitFrame()
{
Active = false;
finishEvent.Set();
waitEvent.WaitOne();
Active = true;
}
}
class Game
{
private readonly List<WorkerThread> workers = new List<WorkerThread>();
public Game()
{
workers.Add(new WorkerThread(this) { Message = "Worker 1" });
workers.Add(new WorkerThread(this) { Message = "Worker 2" });
workers.Add(new WorkerThread(this) { Message = "Worker 3" });
workers.Add(new WorkerThread(this) { Message = "Worker 4" });
workers.Add(new WorkerThread(this) { Message = "Worker 5" });
workers.Add(new WorkerThread(this) { Message = "Worker 6" });
}
public void Start()
{
foreach (WorkerThread worker in workers)
{
worker.Start();
}
}
public void OneFrame()
{
//start every worker
foreach (WorkerThread worker in workers)
{
worker.PerformFrame();
}
//wait for the workers to finish
foreach (WorkerThread worker in workers)
{
worker.WaitForFrameToFinish();
}
//check if there are workers still running
foreach (WorkerThread worker in workers)
{
if (worker.Active)
{
Console.WriteLine(worker.Message + " still active");
}
}
Console.WriteLine("Frame finished.\n");
}
}
Has anyone an idea why the Game doen't wait for the last WorkerThread do finish its task?
EDIT: Using a ManualResetEventSlim instead of an AutoResetEvent solves the problem. But I still don't understand why the above doesn't work.
EDIT 2: I found the answer and posted it below.
I just found the solution. startTask uses the WaitFrame method that sets the finishEvent. That way WaitForFrameToFinish will not wait for the worker on the first iteration because finishEvent is already set.
If you do it like this, it works fine:
private void startTask()
{
waitEvent.WaitOne();
waitEvent.Reset();
finishEvent.Reset();
run();
}

Console application doesn't obey Thread.Join

I'm having trouble understanding why my console app doesn't wait until the thread it spawns fully terminates. I think this is related to the fact that the thread in question also spawns its own child threads and/or the inclusion of System.Timer
The basic program flow is as follows. Main creates a new thread against the Simulator.Start method, and then joins until that thread terminates. Simulator.Start creates a new Timer (to constrain how long it should execute) and then creates/runs a bunch of child threads. When the Elapsed event is raised by the Timer, this signals that the Simulator should terminate all of its child threads and generate a report. The problem is that the console app exits as soon as all child threads terminate and the code to generate a report never gets executed (See Simulator.Stop method below).
Hopefully some pseudo code will help:
public class Program
{
private static Simulator _simulator;
private static void Main(string[] args)
{
var options = new SimulationOptions();
//check for valid options
if (!Parser.Default.ParseArguments(args, options)) return;
_simulator = new Simulator(options);
var thread = new Thread(_simulator.Start) {IsBackground = false};
thread.Start();
thread.Join();
}
}
public class Simulator
{
private readonly SimulationOptions _options;
private readonly List<Thread> _threads = new List<Thread>();
private readonly List<Worker> _workers = new List<Worker>();
private static Timer _timer;
public Simulator(SimulationOptions options)
{
_options = options;
StartTimer(_options.LengthOfTest);
}
private void StartTimer(int lengthOfTest)
{
_timer = new Timer {Interval = lengthOfTest*1000};
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
Stop();
}
public void Stop()
{
// Request that the worker thread stop itself:
foreach (Worker worker in _workers)
{
worker.RequestStop();
}
GenerateReport(); //<-- this code never gets executed
}
private XDocument GenerateReport()
{
//build an awesome report
}
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
}
}
public class Worker
{
private bool _shouldStop = false;
public void PumpMessages()
{
while (!_shouldStop)
{
//does cool stuff until told to stop
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
Nothing in your start method keeps the thread alive. When the following method finishes, so does the thread. You then call Thread.Join and that is the end of that.
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
}
If you intend on waiting for this work to complete, consider waiting on a ManualResetEvent for each worker thread that you are using.
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
http://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitall.aspx
Your method should look something like the following.
public void Start()
{
_threads.Clear();
_workers.Clear();
var evts = new List<ManualResetEvent>()
for (int i = 0; i < _options.NumberOfClients; i++)
{
ManualResetEvent evt = new ManualResetEvent(false);
evts.Add(evt);
_workers.Add(new Worker(evt));
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
WaitHandle.WaitAll(evts.ToArray());
}
public class Worker
{
private bool _shouldStop = false;
private readonly ManualResetEvent #event;
public Worker(ManualResetEvent #event)
{
this.#event = #event;
}
public void PumpMessages()
{
while (!_shouldStop)
{
//does cool stuff until told to stop
}
#event.Set();
}
public void RequestStop()
{
_shouldStop = true;
}
}
Join method waits only for thread instance you joined, so Simulator.Start just creates some threads and it terminates, as the result Join returns and your main thread terminates. But still your App is alive(reason some other Foreground threads are still running).
generate a report never gets executed? Why?
Process will terminate when all Foreground Threads terminates. so as soon as your child threads return from PumpMessages method when you call RequestStop in a loop, all of your foreground threads terminates
public void Stop()
{
// Request that the worker thread stop itself:
foreach (Worker worker in _workers)
{
worker.RequestStop();
}
<--here all foreground threads are ready to terminate
GenerateReport(); //<-- this code never gets executed
}
It was little misleading that I stated that all foreground threads die after the loop. To make it clear let's say that we have given instruction for the worker threads to stop working, so all threads may or may not die before executing GenerateReport method. yes there is a Race If worker threads wins the race then we lose it, and viceversa. sometimes your GenerateReport may execute without any problem.
How to fix it? We just wait for all our worker threads to terminate. that's it.
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
foreach (var t in _threads)
t.Join();
}

Waiting for a 3rd party thread to finish

I need to call a 3rd party code that optionally starts a new thread, performs some processing, and then calls a different method on my object. What I need is wait for the 3rd party processing to be finished, then return from the original method. In other words, I have a class like this (C#):
class MyClass: IThirdPartyInterface {
void MyMethod() {
//some preprocessing
//call a 3rd party static method
ThirdParty.DoSomething(this);
}
void FinishedProcessing() {
//some postprocessing
//???
}
}
I want to modify MyMethod so that it return only after the thread that started in DoSomething has finished its execution and called the FinishedProcessing method. Since the thread is started by the third party code, I don't have access to it, so I cannot use Thread.Join here. So, what do I do instead?
You need to use an System.Threading.AutoResetEvent, it would be like this:
class MyClass: IThirdPartyInterface {
AutoResetEvent _event = new AutoResetEvent(false);
void MyMethod() {
ThirdParty.DoSomething(this);
_event.WaitOne();
}
void FinishedProcessing() {
_event.Set();
}
}
If the thread continues running after your FinishedProcessing method is called by the 3rdparty class, it would be a little diferent:
class MyClass: IThirdPartyInterface {
AutoResetEvent _event = new AutoResetEvent(false);
Thread _thread;
void MyMethod() {
ThirdParty.DoSomething(this);
_event.WaitOne();
_thread.Join();
}
void FinishedProcessing() {
_thread = Thread.CurrentThread;
_event.Set();
}
}
Make your MyMethod() async and then run thirdparty method inside your custom await method, moething like this:
private async void MyMethod()
{
var result = await WaitAsynchronouslyAsync();
}
public async Task<string> WaitAsynchronouslyAsync()
{
await ThirdParty.DoSomething(this);
return "Finished";
}
If ThirdParty.DoSomething does not support async pattern
you can use additional proxy with finalizer.
But it could affect application performance like a "while(myBoolFlag){}".
class Program
{
static void Main(string[] args)
{
var list = new List<ManualResetEvent>();
for (var i = 0; i < 10000; i++)
{
var m = new ManualResetEvent(false);
list.Add(m);
new Thread(Start).Start(m);
if (i > 0 && (i % 10) == 0)
for (int j = i - 10; j < i; j++)
{
list[j].WaitOne(1000);// wait signal
GC.Collect(); //force finalizer
A.Print();
}
}
}
private static void Start(object obj)
{
new A(obj as ManualResetEvent, null);
}
}
public class A : IThirdPartyInterface
{
public static long time1;
public static long count1;
private DateTime start = DateTime.Now;
private ManualResetEvent _stop;
private IThirdPartyInterface _origin;
public A(ManualResetEvent stop, IThirdPartyInterface origin)
{
_stop = stop;
_origin = origin;
}
~A()
{
Interlocked.Increment(ref count1);
Interlocked.Add(ref time1, (long)(DateTime.Now - start).TotalMilliseconds);
_stop.Set(); //send signal
}
public static void Print()
{
Console.Write("\r" + A.time1 + "\\" + A.count1 + " ");
if (A.count1 != 0)
Console.Write((A.time1 / A.count1).ToString());
}
}

Synchronization Exception

I have two threads, one thread processes a queue and the other thread adds stuff into the queue.
I want to put the queue processing thread to sleep when its finished processing the queue
I want to have the 2nd thread tell it to wake up when it has added an item to the queue
However these functions call System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code on the Monitor.PulseAll(waiting); call, because I havent synchronized the function with the waiting object. [which I dont want to do, i want to be able to process while adding items to the queue]. How can I achieve this?
Queue<object> items = new Queue<object>();
object waiting = new object();
1st Thread
public void ProcessQueue()
{
while (true)
{
if (items.Count == 0)
Monitor.Wait(waiting);
object real = null;
lock(items) {
object item = items.Dequeue();
real = item;
}
if(real == null)
continue;
.. bla bla bla
}
}
2nd Thread involves
public void AddItem(object o)
{
... bla bla bla
lock(items)
{
items.Enqueue(o);
}
Monitor.PulseAll(waiting);
}
The answer is in the error message you posted:
"Object synchronization method was called from an unsynchronized block of code on the Monitor.PulseAll(waiting);"
You have to call Monitor.PulseAll(waiting) from inside the lock(waiting) block.
Also... you have to call Monitor.Wait from within a lock block as well.
If you have access to .NET 4.0, what you want to do can be achieved by BlockingCollection<T>.
If you want to do it yourself by means of the Monitor class and signaling with Pulse(), you are actually on the right track.
You get the exception because to call Wait(), Pulse() and PulseAll(), you have to own the lock on the specified object. You happen to miss this on waiting.
A sample basic thread-safe queue that can be used:
with foreach on the consumer,
with while or your favorite conditional construct on the producer side,
handles multiple producers/consumers and
uses lock(), Monitor.Pulse(), Monitor.PulseAll() and Monitor.Wait():
.
public class SignaledQueue<T>
{
Queue<T> queue = new Queue<T>();
volatile bool shutDown = false;
public bool Enqueue(T item)
{
if (!shutDown)
{
lock (queue)
{
queue.Enqueue(item);
//Pulse only if there can be waiters.
if (queue.Count == 1)
{
Monitor.PulseAll(queue);
}
}
return true;
}
//Indicate that processing should stop.
return false;
}
public IEnumerable<T> DequeueAll()
{
while (!shutDown)
{
do
{
T item;
lock (queue)
{
//If the queue is empty, wait.
if (queue.Count == 0)
{
if (shutDown) break;
Monitor.Wait(queue);
if (queue.Count == 0) break;
}
item = queue.Dequeue();
}
yield return item;
} while (!shutDown);
}
}
public void SignalShutDown()
{
shutDown = true;
lock (queue)
{
//Signal all waiting consumers with PulseAll().
Monitor.PulseAll(queue);
}
}
}
Sample usage:
class Program
{
static void Main(string[] args)
{
int numProducers = 4, numConsumers = 2;
SignaledQueue<int> queue = new SignaledQueue<int>();
ParameterizedThreadStart produce = delegate(object obj)
{
Random rng = new Random((int)obj);
int num = 0;
while (queue.Enqueue(++num))
{
Thread.Sleep(rng.Next(100));
}
};
ThreadStart consume = delegate
{
foreach (int num in queue.DequeueAll())
{
Console.Write(" {0}", num);
}
};
Random seedRng = new Random();
for (int i = 0; i < numProducers; i++)
{
new Thread(produce).Start(seedRng.Next());
}
for (int i = 0; i < numConsumers; i++)
{
new Thread(consume).Start();
}
Console.ReadKey(true);
queue.SignalShutDown();
}
}
Use Semaphore http://msdn.microsoft.com/library/system.threading.semaphore.aspx it was designed exactly for this
I prefer to use a callback that launches a processing thread that continues until it's caught up, with locks causing simultaneous readers and writers to wait in line:
public delegate void CallbackDelegate();
class Program
{
static void Main(string[] args)
{
Queue<object> items = new Queue<object>();
Processor processor = new Processor(items);
Adder adder = new Adder(items, new CallbackDelegate(processor.CallBack));
Thread addThread = new Thread(new ParameterizedThreadStart(adder.AddItem));
object objectToAdd = new object();
addThread.Start(objectToAdd);
}
}
class Processor
{
Queue<object> items;
public Processor(Queue<object> itemsArg)
{
items = itemsArg;
}
public void ProcessQueue()
{
lock (items)
{
while (items.Count > 0)
{
object real = items.Dequeue();
// process real
}
}
}
public void CallBack()
{
Thread processThread = new Thread(ProcessQueue);
processThread.IsBackground = true;
processThread.Start();
}
}
class Adder
{
Queue<object> items;
CallbackDelegate callback;
public Adder(Queue<object> itemsArg, CallbackDelegate callbackArg)
{
items = itemsArg;
callback = callbackArg;
}
public void AddItem(object o)
{
lock (items) { items.Enqueue(o); }
callback();
}
}

Categories