Waiting for a 3rd party thread to finish - c#

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());
}
}

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);
}
}

Properly dispose of event producer from a different thread

This is SIMPLIFIED code just illustrating a problem I am trying to solve (haven't compiled it so please ignore any syntax errors). Suppose I have a ProducerProxy like:
public class ProducerProxy : IDisposable {
public event EventHandler<EventArgs> NotificationEvent;
private volatile bool itsKeepProducing = true;
public DoStuff() {
Task.Factory.StartNew(() => {
while (itsKeepProducing) {
RaiseNotificationEvent();
Thread.Sleep(100);
}
}
}
public void Dispose() {
itsKeepProducing = false;
DestroySomeStuff();
}
}
Suppose I now have a class that uses this ProducerProxy:
public class Consumer : IDisposable {
private ProducerProxy itsProducerProxy;
public void Consumer() {
itsProducerProxy = new ProducerProxy();
itsProducerProxy.NotificationEvent += OnNotificationEvent;
}
public void Start() {
itsProducerProxy.DoStuff();
}
public void OnNotificationEvent(object sender, EventArgs args) {
DealWithNotification(args); //this could take some time maybe 1-2 seconds
}
public void Dispose() {
//how do I dispose of the producer here?
//I can't just do the following because notifications might still be processing in OnNotification event:
if (itsProducerProxy != null) {
itsProducerProxy.NotificationEvent -= OnNotificationEvent;
itsProducerProxy.Dispose();
itsProducerProxy = null;
}
}
So my use case is (yes, it should be done using try/catch or using using but that distracts from the question -- just illustrating a point)
var consumer = new Consumer();
consumer.Start();
... //do some stuff
consumer.Dispose();
What is the correct/proper thread-safe implementation for Consumer.Dispose()? or maybe for Producer.Dispose()?
You can use the cooperative thread cancellation pattern by passing in a CancellationToken into your process...
public class Consumer : IDisposable {
private ProducerProxy itsProducerProxy;
// how we signal others that we are disposed
private CancellationTokenSource _cts = new CancellationTokenSource();
/* SNIP */
public void OnNotificationEvent(object sender, EventArgs args) {
// We now provide the inner process with the cancellation token
DealWithNotification(_cts.Token);
}
public void Dispose()
{
// not thread safe but you get the gist
if (_cts!= null) {
_cts.Cancel();
_cts.Dispose();
_cts = null;
}
/* SNIP */
}
}
where the inner process short circuits when cancellation has been requested
private void DealWithNotification(CancellationToken token)
{
if(token.IsCancellationRequested) return;
var foo = "omgwtflol" + bar;
if(token.IsCancellationRequested) return;
Thread.Sleep(2);
if(token.IsCancellationRequested) return;
var reallyEveryTime = File.ReadAllBytes(foo);
if(token.IsCancellationRequested) return;
foreach(var b in reallyEveryTime)
{
if(token.IsCancellationRequested) return;
InnerProcess(token);
}
// etc etc etc you get the idea
}

Joining a thread started with StartNew()

When using the StartNew() method to kick off a process on a new thread, I need to figure out how to make another call into this object in that same thread (I assume this would be some sort of Join operation?).
The following example is dumbed down to illustrate the meat of what I am trying to do. I am well aware it is severely lacking in basic concurrency considerations. But I didn't want to cloud the code with all of that logic, so please forgive me on that.
The following console app shows what I am trying to accomplish. Assume on the StartNew() call a new thread with ID 9976 is created and the method invoked there. I would like the subsequent call to ProcessImmediate() in the file system watcher change event handler to be made on thread 9976 as well. As it stands, the call would share the same thread that is used for the file system watcher change event.
Can this be done, and if so, how?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
public void Run()
{
_activity = new Activity();
// start activity on a new thread
Task.Factory.StartNew(() => _activity.Go());
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "c:\temp";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity
{
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
System.Threading.Thread.Sleep(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
DoSomethingInteresting();
}
public bool Stop { get; set; }
}
}
* UPDATE *
Thanks for the excellent responses. I took Mike's suggestion and implemented it for my console app. Below is the full working code which also includes the use of a cancellation token. I post this in case someone else might find it useful.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
runner.Stop();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
private CancellationTokenSource _cts = new CancellationTokenSource();
public void Stop() { _cts.Cancel(); }
public void Run()
{
_activity = new Activity();
// start activity on a new thread
var task = new Task(() => _activity.Go(_cts.Token), _cts.Token, TaskCreationOptions.LongRunning);
task.Start();
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "C:\\Temp\\FileSystemWatcherPath";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go(CancellationToken ct)
{
Thread.CurrentThread.Name = "Go";
while (!ct.IsCancellationRequested)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(5000);
}
Console.WriteLine("Exiting");
}
protected virtual void DoSomethingInteresting()
{
Console.WriteLine(string.Format("Doing Something Interesting on thread {0}", Thread.CurrentThread.ManagedThreadId));
}
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
_processing.Set();
}
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
}
First, you should use TaskCreationOptions.LongRunning if you are creating a task that will not complete quickly. Second, use an AutoResetEvent to signal the waiting thread to wake up. Note that below ProcessImmediate will return before DoSomethingInteresting has completed running on the other thread. Example:
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
User mike has given a better solution, which will be appropriate when you like to call the same method immediately. If you want to call a different methods immediately I'll expand mike's answer to achieve that.
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
private ConcurrentQueue<Action> actionsToProcess = new ConcurrentQueue<Action>();
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
while(!actionsToProcess.IsEmpty)
{
Action action;
if(actionsToProcess.TryDeque(out action))
action();
}
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate(Action action)
{
actionsToProcess.Enqueue(action);
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
To execute different methods on the same thread you can use a message loop that dispatches incoming requests. A simple option would be to use the event loop scheduler of the Reactive Extensions and to "recursively" schedule your Go() function - if in the mean time a different operation is scheduled it would be processed before the next Go() operation.
Here is a sample:
class Loop
: IDisposable
{
IScheduler scheduler = new EventLoopScheduler();
MultipleAssignmentDisposable stopper = new MultipleAssignmentDisposable();
public Loop()
{
Next();
}
void Next()
{
if (!stopper.IsDisposed)
stopper.Disposable = scheduler.Schedule(Handler);
}
void Handler()
{
Thread.Sleep(1000);
Console.WriteLine("Handler: {0}", Thread.CurrentThread.ManagedThreadId);
Next();
}
public void Notify()
{
scheduler.Schedule(() =>
{
Console.WriteLine("Notify: {0}", Thread.CurrentThread.ManagedThreadId);
});
}
public void Dispose()
{
stopper.Dispose();
}
}
static void Main(string[] args)
{
using (var l = new Loop())
{
Console.WriteLine("Press 'q' to quit.");
while (Console.ReadKey().Key != ConsoleKey.Q)
l.Notify();
}
}

Frequent lag spikes in multi-threaded code

I'm attempting to make my simple C# graphics library multi-threaded. However, after the introduction of this code:
/* foreach (IAffector affector in affectorLookup.Values)
affector.Update(timestep); */
taskManager.Value = timestep; taskManager.Start();
foreach (IAffector affector in affectorLookup.Values)
taskManager.AddToQueue(affector.Update);
taskManager.StopWhenDone();
taskManager.Wait();
the simulation starts experiencing sharp lag-spikes, which seem to originate in TaskHandler.Run (I can't tell for sure, because adding the previous code makes my code profiler ignore anything outside TaskHandler.Run).
The task manager:
public class TaskManager
{
public delegate void MethodDel(float timestep);
private Queue<MethodDel> queue;
private List<TaskHandler> handlers;
private float value;
public float Value
{
get
{
return value;
}
set
{
this.value = value;
}
}
public TaskManager()
{
this.queue = new Queue<MethodDel>();
this.handlers = new List<TaskHandler>(System.Environment.ProcessorCount);
for (int t = 0; t < this.handlers.Capacity; ++t)
this.handlers.Add(new TaskHandler(this));
this.value = 0;
}
public void Start()
{
foreach (var handler in handlers)
handler.Start();
}
public void Stop()
{
lock (queue)
queue.Clear();
foreach (var handler in handlers)
handler.StopWhenDone();
}
public void StopWhenDone()
{
foreach (var handler in handlers)
handler.StopWhenDone();
}
public void AddToQueue(MethodDel method)
{
lock (queue)
queue.Enqueue(method);
}
public bool GetFromQueue(out MethodDel method)
{
lock (queue)
{
if (queue.Count == 0) { method = null; return false; }
method = queue.Dequeue();
return true;
}
}
public int GetQueueCount()
{
return queue.Count;
}
internal void Wait()
{
// Have to wait for them one at a time because the main thread is STA.
WaitHandle[] waitHandles = new WaitHandle[1];
// for (int t = 0; t < handlers.Count; ++t)
// waitHandles[t] = handlers[t].WaitHandle;
// WaitHandle.WaitAll(waitHandles);
for (int t = 0; t < handlers.Count; ++t)
{ waitHandles[0] = handlers[t].WaitHandle; WaitHandle.WaitAll(waitHandles); }
}
}
And the task handler:
public class TaskHandler
{
private TaskManager manager;
private Thread thread;
private bool stopWhenDone;
private ManualResetEvent waitHandle;
public ManualResetEvent WaitHandle
{
get
{
return waitHandle;
}
}
public TaskHandler(TaskManager manager)
{
this.manager = manager;
}
public void Start()
{
waitHandle = new ManualResetEvent(false);
stopWhenDone = false;
thread = new Thread(Run);
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.MTA);
thread.Start();
}
public void StopWhenDone()
{
this.stopWhenDone = true;
}
// Possible source of slowdown
private void Run()
{
TaskManager.MethodDel curMethod;
while (!stopWhenDone || manager.GetQueueCount() > 0)
{
if (manager.GetFromQueue(out curMethod))
{
curMethod(manager.Value);
}
}
waitHandle.Set();
}
}
Starting a thread is a heavy operation. Not sure if it's as heavy as you are experiencing, but that could be it. Also, having all your processing run parallel can be putting a big strain on your system with possibly little benefit...
I'm going to venture that the spikes have something to do with waitHandle.Set();
I like the overall design, but I have not used WaitHandle before, so I am unsure how this interacts with your design.

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