How to handle signal once in many threads in C#
In C# I have multiple objects, each with its own thread, that can perform an operation based on outside signal. All of the object keep a list of all other objects.
I need the signal that arrived to be performed only in single object in single thread. This signal will bring to the deletion of all objects so multiple signals 开发者_Python百科won't arrive for the same object. It's most likely the signal will arrive for all of them in the same time, but there can be late ones. As the signal will bring to the destruction of all of them and will not be delivered to destroyed ones, latencies can be ignored. I though of doinglock(this)
and then lock on each object in the list but I don't know how to perform lock without creating a scope for it (meaning manual unlock, not when the lock scope ends).
Additional problem is that if already one has started locking and the other one tries to lock it, it will just wait and not ignore it.
Also, I have no control on the Thread
objects and even if there is a way to retrieve them any touch on the Thread
object will likely crash the application. Answers like pausing all other threads will not work.
So how do I get the signal acted upon by exactly one object and ignore by the rest of them?You could have a parent thread that keeps track of what has been processed. When a thread receives a new signal, you can ask the parent if that signal has been processed already. If not, process it and parent locks the others out.
You could also look at using a message queue, and each signal would only be picked up by one thread.
I think I understand what's going on now, but correct me if this is wrong:
- presumably all your objects are of the same type
- the list of objects is static (if not, then consider doing it to be more efficient)
- any object can receive the signal, but only one will process it.
So if we assume that you each object has a method to receive a signal, then I would think this might be a decent design:
public class Thing
{
private static volatile bool _tooLate = false;
private static List<Thing> _theWorld; // contains everything
private static readonly object _sync = new object();
public Thing(){/*...*/}
// a static method to process the signal
public static void ProcessSignal(Signal signal)
{
// make sure you're not late to the party
if(signal == signal.DestroyTheWorld && !_tooLate)
{
// You won't destroy the world yet... but you'll give it a shot!
BringAboutTheDestruction();
}
}
// a static method to bring about the destruction of the world! MUAHAHAHAHA
public static void BringAboutTheDestruction()
{
// you might not be late for the party,
// but you still have to get past the doorman
lock(_sync)
{
// you finally got in, but you might get kicked out!
if(!_tooLate)
{
// Apocalypse now!!! There is no turning back
foreach(Thing t in _theWorld)
{
t.Destroy();
}
_theWorld.Clear();
}
_tooLate = true;
}
}
}
You can always use the EventWaitHandle class. Each thread has two of these, one when the thread needs to do something, and one for closing all the threads. The first is local to the thread, the second is global:
void CreateThreads ()
{
global_event = new EventWaitHandle (false, EventResetMode.AutoReset);
for each thread to create
{
create thread a pass the global_event object
}
}
void ThreadProc (EventWaitHandle global_event)
{
create local_event; // this is set when the thread needs to do something
bool quit = false;
while (!quit)
{
switch (EventWaitHandle.WaitAny (new WaitHandle [] { global_event, local_event })
{
case 0: // global
shut down other threads
quit = true;
break;
case 1: // local
do local signal processing
break;
}
}
}
The EventResetMode.AutoReset flag means that only one out of all the threads waiting on the event will be released. Of course, you can't predict which one.
精彩评论