C#マルチスレッド(6):スレッド通知

確認するために、lockセクションとMonitorセクションでのスレッドロック、Mutexセクションでのプロセスの同期、Semaphorセクションでのリソースプールの制限について学びました。

この記事では、スレッド通知を送信するためのC#のAutoRestEventクラスについて学習します。

AutoRestEventクラス

あるスレッドから別のスレッドに通知を送信するために使用されます。

Microsoftのドキュメントでは、このように説明しています。つまり、待機中のスレッドが解放された後にシグナルを受信すると、スレッド同期イベントが自動的にリセットされます。

コンストラクタは1つしかありません。

コンストラクターのパラメーターは、信号の状態を設定するために使用されます。

コンストラクター 解説
AutoResetEvent(ブール) 初期状態を終了に設定するかどうかを示すブール値を使用して、AutoResetEventクラスの新しいインスタンスを初期化します。

なんとひどい機械翻訳でしょう。

一般的な方法

AutoRestEventクラスとは何ですか?コンストラクターのパラメーターは何ですか?心配しないで、このクラスの一般的に使用されるメソッドを見てみましょう:

方法 解説
閉じる() 現在のWaitHandleによって占有されているすべてのリソースを解放します。
リセット() イベントステータスを非終了に設定すると、スレッドがブロックされます。
セットする() イベントステータスを通知済みに設定し、1つ以上の待機中のスレッドが実行を継続できるようにします。
WaitOne() 現在のWaitHandleがシグナルを受信するまで、現在のスレッドをブロックします。
WaitOne(Int32) 現在のWaitHandleがシグナルを受信するまで現在のスレッドをブロックし、32ビットの符号付き整数を使用して時間間隔(ミリ秒単位)を指定します。
WaitOne(Int32、Boolean) 現在のWaitHandleが信号を受信するまで現在のスレッドをブロックし、32ビットの符号付き整数を使用して時間間隔を指定し、待機する前に同期ドメインを終了するかどうかを指定します。
WaitOne(TimeSpan) 現在のインスタンスがシグナルを受信するまで現在のスレッドをブロックし、TimeSpanを使用して時間間隔を指定します。
WaitOne(TimeSpan、Boolean) 現在のインスタンスが信号を受信するまで現在のスレッドをブロックし、TimeSpanを使用して時間間隔を指定し、待機する前に同期ドメインを終了するかどうかを指定します。

簡単な例

ここでは、次のようなプログラムを作成します。

複数のフェーズでタスクを実行できるスレッドを作成します。フェーズを完了するたびに、子スレッドからの通知を停止して待機してから、次のステップに進む必要があります。

.WaitOne() 別のスレッドが通知を送信するのを待つために使用されます。

.Set()スレッドに通知し、この場合には、AutoResetEvent終了条件になります。

.ReSet()これは、リセットするために使用AutoResetEvent状態を、

    class Program
    {
        // 线程通知
        private static AutoResetEvent resetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            // 创建线程
            new Thread(DoOne).Start();

            // 用于不断向另一个线程发送信号
            while (true)
            {
                Console.ReadKey();
                resetEvent.Set();           // 发生通知,设置终止状态
            }
        }

        public static void DoOne()
        {
            Console.WriteLine("等待中,请发出信号允许我运行");

            // 等待其它线程发送信号
            resetEvent.WaitOne();

            Console.WriteLine("\n     收到信号,继续执行");
            for (int i = 0; i < 5; i++) Thread.Sleep(TimeSpan.FromSeconds(0.5));

            resetEvent.Reset(); // 重置为非终止状态
            Console.WriteLine("\n第一阶段运行完毕,请继续给予指示");

            // 等待其它线程发送信号
            resetEvent.WaitOne();
            Console.WriteLine("\n     收到信号,继续执行");
            for (int i = 0; i < 5; i++) Thread.Sleep(TimeSpan.FromSeconds(0.5));

            Console.WriteLine("\n第二阶段运行完毕,线程结束,请手动关闭窗口");
        }
    }

説明する

AutoResetEventオブジェクトには、終了ステータスと非終了ステータスがあります。Set()終了状態をReset()設定し、非終了状態をリセットします。

この終了状態は、信号が通知されているため理解できますが、非終了状態は、信号が通知されていない状態です。

終了状態と非終了状態は、スレッドの状態ではなく、AutoResetEventの状態を参照することに注意してください。

スレッドは、WaitOne()メソッドを呼び出してシグナルを待ちます。
別のスレッドはSet()を呼び出して、待機中のスレッドを解放するようにAutoResetEventに通知できます。
次に、AutoResetEventが終了状態になります。

なお、もしAutoResetEvent既に最終状態では、スレッドの呼び出しWaitOne()は動作しません。呼ばれない限りReset()

コンストラクターのパラメーターがこの状態を設定します。trueは終了状態を表し、falseは非終了状態を表します。使用したnew AutoResetEvent(true);場合、スレッドは最初にシグナルを待つ必要はありません。

型を使用した後は、リリースの種類、明示的な呼び出し直接または間接的にすべきClose()/Dispose()か、使用をusingもちろん、プログラムを直接終了することもできます。

複数の呼び出しの場合、なお、Set()第一の場合の時間間隔が、短すぎるSet()(信号伝送が処理時間を必要とする)上にまだないが、第2のSet()(動作しない)が無効であってもよいです。

より複雑な例

私たちはプログラムを設計します:

  • 2つのスレッドがブロックされ始めました。
  • スレッド1は、スレッド2を設定して実行を継続し、それ自体をブロックすることができます。
  • スレッド2は、実行を継続してそれ自体をブロックするように1を設定できます。

プログラムコードは次のとおりです(実行後、キーボードを英語の入力状態に設定してからキーを押してください)。

    class Program
    {
        // 控制第一个线程
        // 第一个线程开始时,AutoResetEvent 处于终止状态,无需等待信号
        private static AutoResetEvent oneResetEvent = new AutoResetEvent(true);

        // 控制第二个线程
        // 第二个线程开始时,AutoResetEvent 处于非终止状态,需要等待信号
        private static AutoResetEvent twoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            new Thread(DoOne).Start();
            new Thread(DoTwo).Start();

            Console.ReadKey();
        }

        public static void DoOne()
        {
            while (true)
            {
                Console.WriteLine("\n① 按一下键,我就让DoTwo运行");
                Console.ReadKey();
                twoResetEvent.Set();
                oneResetEvent.Reset();
                // 等待 DoTwo() 给我信号
                oneResetEvent.WaitOne();

                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("\n     DoOne() 执行");
                Console.ForegroundColor = ConsoleColor.White;
            }
        }

        public static void DoTwo()
        {
            while (true)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));

                // 等待 DoOne() 给我信号
                twoResetEvent.WaitOne();

                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("\n     DoTwo() 执行");
                Console.ForegroundColor = ConsoleColor.White;

                Console.WriteLine("\n② 按一下键,我就让DoOne运行");
                Console.ReadKey();
                oneResetEvent.Set();
                twoResetEvent.Reset();
            }
        }
    }

説明する

2つのスレッドが持つ機能:自分自身のブロックと別のスレッドのブロック解除。

映画「ベストパートナー」の写真を使用して理解します。

DoOneとDoTwoは交互に呼吸を行いますが、自分の呼吸を制御することはできませんが、呼吸を決定することはできます。

あなたは私をファック、私はあなたをファック、あなたはお互いを呼吸することができます。

もちろんWaitOne()待ち時間を設定することもできDoOneがDoTwoの呼吸を許可しない場合は、一定時間待機した後、バジュラがバランスを強制して床の上で呼吸することができます。

AutoRestEventを不適切に使用すると、デッドロックが発生しやすくなることに注意してください。
さらに、AutoRestEventはカーネル時間モードを使用するため、待機時間が長くなりすぎないようにしてください。そうしないと、CPU時間を消費します。

AutoResetEventは、スレッドの同期にも適しています。

さらに、スレッドの使用はWaitOne()、使用して別のスレッドSet()の通知は、オブジェクトは自動的に、スレッドの使用を必要としない、AutoResetEventの非終了状態を復元しますReset()

おすすめ

転載: www.cnblogs.com/whuanle/p/12730169.html