日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【转】细说.NET中的多线程 (五 使用信号量进行同步)

發布時間:2023/12/10 asp.net 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】细说.NET中的多线程 (五 使用信号量进行同步) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一節主要介紹了使用鎖進行同步,本節主要介紹使用信號量進行同步

使用EventWaitHandle信號量進行同步

EventWaitHandle主要用于實現信號燈機制。信號燈主要用于通知等待的線程。主要有兩種實現:AutoResetEvent和ManualResetEvent。

AutoResetEvent

AutoResetEvent從字面上理解是一個自動重置的事件。舉個例子,假設有很多人等在門外,AutoResetEvent更像一個十字旋轉門,每一次只允許一個人進入,進入之后門仍然是關閉狀態。

下面的例子演示了使用方式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

using?System;

using?System.Threading;

class?BasicWaitHandle

{

????static?EventWaitHandle _waitHandle =?new?AutoResetEvent(false);

?

????static?void?Main()

????{

????????for?(int?i = 0; i < 3; i++)

????????????new?Thread(Waiter).Start();

?

????????for?(int?i = 0; i < 3; i++)

????????{

????????????Thread.Sleep(1000);??????????????????// Pause for a second...

????????????Console.WriteLine("通知下一個線程進入");

????????????_waitHandle.Set();????????????????????// Wake up the Waiter.

????????}

????????Console.ReadLine();

????}

?

????static?void?Waiter()

????{

????????var?threadId = Thread.CurrentThread.ManagedThreadId;

????????Console.WriteLine("線程 {0} 正在等待", threadId);

????????_waitHandle.WaitOne();????????????????// 等待通知

????????Console.WriteLine("線程 {0} 得到通知,可以進入", threadId);

????}

}

  

雙向信號燈

某些情況下,如果你連續的多次使用Set方法通知工作線程,這個時候工作線程可能還沒有準備好接收信號,這樣的話后面的幾次Set通知可能會沒有效果。這種情況下,你需要讓主線程得到工作線程接收信息的通知再開始發送信息。你可能需要通過兩個信號燈實現這個功能。

示例代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

using?System;

using?System.Threading;

class?TwoWaySignaling

{

????static?EventWaitHandle _ready =?new?AutoResetEvent(false);

????static?EventWaitHandle _go =?new?AutoResetEvent(false);

????static?readonly?object?_locker =?new?object();

????static?string?_message;

?

????static?void?Main()

????{

????????new?Thread(Work).Start();

?

????????_ready.WaitOne();??????????????????// 在工作線程準備接收信息之前需要一直等待

????????lock?(_locker) _message =?"床前明月光";

????????_go.Set();?????????????????????????// 通知工作線程開始工作

?

????????_ready.WaitOne();

????????lock?(_locker) _message =?"疑是地上霜";

????????_go.Set();

????????_ready.WaitOne();

????????lock?(_locker) _message =?"結束";????// 告訴工作線程退出

????????_go.Set();

?

????????Console.ReadLine();

????}

?

????static?void?Work()

????{

????????while?(true)

????????{

????????????_ready.Set();??????????????????????????// 表示當前線程已經準備接收信號

????????????_go.WaitOne();?????????????????????????// 工作線程等待通知

????????????lock?(_locker)

????????????{

????????????????if?(_message ==?"結束")?return;????????// 優雅的退出~-~

????????????????Console.WriteLine(_message);

????????????}

????????}

????}

}

生產消費隊列

生產消費隊列是多線程編程里常見的的需求,他的主要思路是:

  • 一個隊列用來存放工作線程需要用到的數據
  • 當新的任務加入隊列的時候,調用線程不需要等待工作結束
  • 1個或多個工作線程在后臺獲取隊列中數據信息
  • 示例代碼:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    using?System;

    using?System.Threading;

    using?System.Collections.Generic;

    ??

    class?ProducerConsumerQueue : IDisposable

    {

    ??EventWaitHandle _wh =?new?AutoResetEvent (false);

    ??Thread _worker;

    ??readonly?object?_locker =?new?object();

    ??Queue<string> _tasks =?new?Queue<string>();

    ??

    ??public?ProducerConsumerQueue()

    ??{

    ????_worker =?new?Thread (Work);

    ????_worker.Start();

    ??}

    ??

    ??public?void?EnqueueTask (string?task)

    ??{

    ????lock?(_locker) _tasks.Enqueue (task);

    ????_wh.Set();

    ??}

    ??

    ??public?void?Dispose()

    ??{

    ????EnqueueTask (null);?????// Signal the consumer to exit.

    ????_worker.Join();?????????// Wait for the consumer's thread to finish.

    ????_wh.Close();????????????// Release any OS resources.

    ??}

    ??

    ??void?Work()

    ??{

    ????while?(true)

    ????{

    ??????string?task =?null;

    ??????lock?(_locker)

    ????????if?(_tasks.Count > 0)

    ????????{

    ??????????task = _tasks.Dequeue();

    ??????????if?(task ==?null)?return;

    ????????}

    ??????if?(task !=?null)

    ??????{

    ????????Console.WriteLine ("Performing task: "?+ task);

    ????????Thread.Sleep (1000);??// simulate work...

    ??????}

    ??????else

    ????????_wh.WaitOne();?????????// No more tasks - wait for a signal

    ????}

    ??}

    }

    為了保證線程安全,我們使用lock來保護Queue<string>集合。我們也顯示的關閉了WaitHandle。

    在.NET 4.0中,一個新的類BlockingCollection實現了類似生產者消費者隊列的功能。

    ManualResetEvent

    ManualResetEvent從字面上看是一個需要手動關閉的事件。舉個例子:假設有很多人等在門外,它像是一個普通的門,門開啟之后,所有等在門外的人都可以進來,當你關閉門之后,不再允許外面的人進來。

    示例代碼:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    using?System;

    using?System.Threading;

    class?BasicWaitHandle

    {

    ????static?EventWaitHandle _waitHandle =?new?ManualResetEvent(false);

    ?

    ????static?void?Main()

    ????{

    ????????for?(int?i = 0; i < 3; i++)

    ????????????new?Thread(Waiter).Start();

    ?

    ?

    ????????Thread.Sleep(1000);??????????????????// Pause for a second...

    ????????Console.WriteLine("門已打開,線程進入");

    ????????_waitHandle.Set();????????????????????// Wake up the Waiter.

    ?

    ????????new?Thread(Waiter).Start();

    ?

    ????????Thread.Sleep(2000);

    ?

    ????????_waitHandle.Reset();

    ????????Console.WriteLine("門已關閉,線程阻塞");

    ?

    ????????new?Thread(Waiter).Start();

    ?

    ????????Console.ReadLine();

    ????}

    ?

    ????static?void?Waiter()

    ????{

    ????????var?threadId = Thread.CurrentThread.ManagedThreadId;

    ????????Console.WriteLine("線程 {0} 正在等待", threadId);

    ????????_waitHandle.WaitOne();????????????????// 等待通知

    ????????Console.WriteLine("線程 {0} 得到通知,可以進入", threadId);

    ????}

    }

    ManualResetEvent可以在當前線程喚醒所有等待的線程,這一應用非常重要。

    CountdownEvent

    CountdownEvent的使用和ManualEvent正好相反,是多個線程共同喚醒一個線程。

    示例代碼:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    using?System;

    using?System.Threading;

    class?CountDownTest

    {

    ????static?CountdownEvent _countdown =?new?CountdownEvent(3);

    ?

    ????static?void?Main()

    ????{

    ????????new?Thread(SaySomething).Start("I am thread 1");

    ????????new?Thread(SaySomething).Start("I am thread 2");

    ????????new?Thread(SaySomething).Start("I am thread 3");

    ?

    ????????_countdown.Wait();???// 當前線程被阻塞,直到收到 _countdown發送的三次信號

    ????????Console.WriteLine("All threads have finished speaking!");

    ?

    ????????Console.ReadLine();

    ????}

    ?

    ????static?void?SaySomething(object?thing)

    ????{

    ????????Thread.Sleep(1000);

    ????????Console.WriteLine(thing);

    ????????_countdown.Signal();

    ????}

    }

    創建跨進程的EventWaitHandle

    EventWaitHandle的構造方法允許創建一個命名的EventWaitHandle,來實現跨進程的信號量操作。名字只是一個簡單的字符串,只要保證不會跟其它進程的鎖沖突即可。

    示例代碼:

    1

    EventWaitHandle wh =?new?EventWaitHandle(false, EventResetMode.AutoReset,?"MyCompany.MyApp.SomeName");

      

    如果兩個進程運行這段代碼,信號量會作用于兩個進程內所有的線程。

    總結

    以上是生活随笔為你收集整理的【转】细说.NET中的多线程 (五 使用信号量进行同步)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。