以執行緒安全方式引發事件 修正

2022-02-16 10:38:22 字數 1719 閱讀 3441

《clr via c#》3rd中提到,應該以執行緒安全的方式引發事件,不禁冒冷汗,一直以來還真沒注意到這個問題,以前寫的不少**得重新審查修正了。下面是引用原文說明:

.net framework最初發布時,是建議開發者用以下方式引發事件:

protected

virtual

void

onnewmail(newmaileventargs e)

這個onnewmail方法的問題在於,執行緒可能發現newmail不為null,然後,就在呼叫newmail之前,另乙個執行緒從委託鏈中移除了乙個委託,是newmail變成了null。這會造成丟擲乙個nullreferenceexception異常。

於是我寫了以下**測試重現這種執行緒競態的情況: 

**

using

system;

using

system.threading;

using

system.diagnostics;

namespace

neutra.utils

static

void

addandremoveeventhandler(

object

obj)

}static

void

handleevent(

object

sender, eventargs e)

static

void

test1()

thread.sleep(0);

}console.writeline();

}catch

(exception exception)

, time:

", i, sw.elapsed);

console.writeline(exception);

}finally

}static

void

test2()

thread.sleep(0);

}console.writeline();

}catch

(exception exception)

, time:

", i, sw.elapsed);

console.writeline(exception);

}finally}}

}

我測試了好幾次,index最小的一次是60多,最大的1000多,併發問題還是比較明顯的。下面是其中一次測試結果:

有些人傾向於使用eventhandler handler = instance.myevent;代替使用interlocked.compareexchange方法,書中也提到了,這種方式也是可行的,因為ms的jit編譯器不會將這裡的handler優化掉。書中最後說道「另外由於事件主要在單執行緒的情形中使用(winform/wpf/silverlight),所以執行緒安全並不是乙個問題。」

我認為,這個問題還是有必要注意一下的。這種問題一般都很難重現,而且還是該死的nullreferenceexception異常,一看上下文**,霎時間還真是「莫名其妙」,最後歸於人品問題倒是相當無奈了。

今天發現**中有誤,interlocked.exchange會交換兩引用,應該使用interlocked.compareexchange方法。(上面**已修正)

以ThreadStart方式實現多執行緒

使用threadstart委託 這裡先以乙個例子體現一下多執行緒帶來的好處,首先在message類中建立乙個方法showmessage 裡面顯示了當前執行執行緒的id,並使用thread.sleep int 方法模擬部分工作。在main 中通過threadstart委託繫結message物件的sho...

由Action是否是執行緒安全的引發的思考

不知道從哪個地方入的口,一直看到action是否是安全的,在網上找了一大通答案。亂的很,有的說action是執行緒安全的,有的說是執行緒不安全的。最後發現,原來說執行緒安全的是基於struts2的,而說執行緒不安全的是基於struts1的。總結 struts1中,每乙個action在web容器中只會...

執行緒安全處理的3種方式

本次電影的座位共 100個 本場電影只能賣100張票 如下 public class tickects implements runnable catch interruptedexception e system.out.println thread.currentthread getname 售...