是否有一个好方法在C#扔一个例外给线
-
09-06-2019 - |
题
代码是我想写的是这样的:
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
我知道我可能有线B的定期检查,在线安全的方式,看看是否一个标志已经设置的线,但是这使得该代码的更加复杂。是否有更好的机制,我可以使用?
这里是一个更加充实例定期检查:
Dictionary<Thread, Exception> exceptionDictionary = new Dictionary<Thread, Exception>();
void ThrowOnThread(Thread thread, Exception ex)
{
// the exception passed in is going to be handed off to another thread,
// so it needs to be thread safe.
lock (exceptionDictionary)
{
exceptionDictionary[thread] = ex;
}
}
void ExceptionCheck()
{
lock (exceptionDictionary)
{
Exception ex;
if (exceptionDictionary.TryGetValue(Thread.CurrentThread, out ex))
throw ex;
}
}
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
ExceptionCheck();
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
解决方案
这不是一个好主意
这篇文章谈到红宝石的超时的图书馆。 这引发了例外的跨线。
它介绍了如何做这样的事是从根本上破坏。这不仅仅是打破在红宝石,这是打破任何地方引发的例外跨线。
简而言之,有什么可以(并的确)发生的情况是这样的:
ThreadA:
At some random time, throw an exception on thread B:
马:
try {
//do stuff
} finally {
CloseResourceOne();
// ThreadA's exception gets thrown NOW, in the middle
// of our finally block and resource two NEVER gets closed.
// Obviously this is BAD, and the only way to stop is to NOT throw
// exceptions across threads
CloseResourceTwo();
}
你的'定期检查的例子是好的,因为你不会真的引发的异常跨线。
你只是设定一个标志,该标志说"把一个异常的下一次你看看这个标志",它是好的,因为它不遭受"可以被扔在你赶上或最后块"的问题。
但是,如果你要这样做,你可能也只是被设定一个"exitnow"的标志,以及使用和保存自己的麻烦的创建除对象。一种挥发性bool会工作得很好。
其他提示
有足够的问题与例外情况,可以扔在线通过其他机制,如中止的线和喜欢的,你应该找到另一种方式这样做。
一个例外是一个机构使用的信号,即一个进程经历了什么特殊的,它不能处理。你应该试图避免编写的代码这样一个例外是用于信号, 别的东西 具有经验丰富的东西。
其他的线很可能不知道如何处理异常 在所有情况下,它可能会引发你的代码.
总之,你应该找到其他一些机构为中止你的螺纹于使用的例外情况。
使用事件的对象或类似告诉一个线程,以中止对其的处理,这是最好的方式。
同时研究的另一个问题,我遇到了这篇文章,其中提醒了我你的问题:
它显示出波动。净进通过实施线。中止()--想必是任何其它的跨线例外必须类似。(Yeech!)
什么猎户座爱德华兹说的是完全不真实的:不是"只"的方式。
// Obviously this is BAD, and the only way to stop is to NOT throw // exceptions across threads
使用核证的排减量(受约束的执行地区)在C#可以让你释放资源作为原子操作,保护你的代码中间线的例外情况。这种技术被用于几种类别。净框架的工作带的Windows的机API,在那里尚未发行的处理可能导致记忆丢失。
下面的示例说明如何可靠地落处理,通过使用 PrepareConstrainedRegions
法。可靠地设置一个处理指定的预现有的处理,必须确保分配的本地处理和随后记录的处理内的一个 SafeHandle
对象是原子的。任何故障之间的这些行动(例如一个线程中止或存储器除外)的结果将在当地处理被泄露。你可以使用 PrepareConstrainedRegions
方法,以确保处理不被泄露。
这么简单:
public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally // this finally block is atomic an uninterruptible by inter-thread exceptions
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}
return sh;
}
我有兴趣知道为什么你想要做这。有没有一个简单的方法来做到这一点,因为它不是一个好的做法。你也许应该回到你的设计和图找出一个更清洁的方式来完成的最终目标。
我不认为这是一个很好的想法..采取的另一个裂缝在这一问题的尝试使用其他一些机制,如共享数据的信号之间的螺纹。
像其他人一样,我不确定这是个好主意,但是如果你真的想这样做,然后您可以创建一个亚类的SynchronizationContext由允许发布和发送代表团到目标的线(如果它是一个它纹的工作是为你做的这样一个子类已经存在的话)。目标线将已经实行某种形式的消息泵等,虽然,对收到的与会代表。
@Orion爱德华兹
我把你的点有关的一个例外被扔在最后块。
然而,我认为有一种方法-利用的又一个螺纹使用这种例外作为中断的想法。
螺纹:
At some random time, throw an exception on thread C:
螺纹B:
try {
Signal thread C that exceptions may be thrown
//do stuff, without needing to check exit conditions
Signal thread C that exceptions may no longer be thrown
}
catch {
// exception/interrupt occurred handle...
}
finally {
// ...and clean up
CloseResourceOne();
CloseResourceTwo();
}
线C:
while(thread-B-wants-exceptions) {
try {
Thread.Sleep(1)
}
catch {
// exception was thrown...
if Thread B still wants to handle exceptions
throw-in-B
}
}
或者是,仅仅是愚蠢的?