プログラムを書こう!

実務や自作アプリ開発で習得した役に立つソフトウェア技術情報を発信するブログ

C++/CLIで排他制御したキューを使う。

この記事は2018年08月09日に投稿しました。

f:id:paveway:20190914064630j:plain

目次

  1. はじめに
  2. 排他制御したキュー
  3. おわりに

世界でいちばん簡単なVisualC++のe本 標準C++とC++/CLIの基本と考え方がわかる本

世界でいちばん簡単なVisualC++のe本 標準C++とC++/CLIの基本と考え方がわかる本

1. はじめに

こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。

今回は業務で使用しているC++/CLIの話です。
シリアル通信を行うアプリで、シリアル通信処理部分と上位(GUI)処理で受信コマンドの受け渡しに排他制御したキューを使用しました。 その時使用した排他制御したキューの実装例です。

目次へ

2. 排他制御したキュー

排他制御したキューは、

を使用して実装しました。

処理の概要ですが、

  • キューQueueオブジェクトに受信コマンド(文字列)をキューイングします。
  • キューQueueオブジェクトに受信コマンドを設定する/取り出す時、モニターMonitorオブジェクトで排他ロックします。
  • 取り出す側は、イベントManualResetEventオブジェクトでイベント待ちします。 設定する側は、設定した時にイベントを発生させ、取り出し側に受信コマンドが設定されたことを通知します。

となります。

以下が使用する手順です。

  1. 上位(GUI)のコマンド待ち処理の中で、WaitMsgメソッドを呼び出し、シリアル通信処理からコマンドが受信されるのを待ちます。
  2. シリアル通信処理でコマンドを受信したとき、SetMsgメソッドでキューにコマンドをセットします。
  3. 2のSetMsgメソッドが呼び出されると、WaitMsgメソッドの待ち状態が解除されます。
    キューに積まれたコマンドを取得して、コマンドに応じた処理を行います。
namespace Util {
    using namespace System;
    using namespace System::Collections;
    using namespace System::Threading;

    ref class QueueUtil
    {
    private:
        /// 自クラスのインスタンス
        static QueueUtil^ instance;

        /// キューオブジェクト
        Queue^ queue;

        /// イベントオブジェクト
        ManualResetEvent^ event;

        /// <summary>
        /// コンストラクタ
        ///
        /// param capacity: キューイングするメッセージの数
        /// </summary>
        QueueUtil(int capacity)
        {
            queue = gcnew Queue(capacity);
            queue->Clear();
            event = gcnew ManualResetEvent(false);
        }

    public:
        /// <summary>
        /// インスタンスを返却します。
        ///
        /// param capacity: キューイングするメッセージの数
        /// </summary>
        static QueueUtil^ GetInstance(int capacity)
        {
            // インスタンスが未精製の場合
            if (instance == nullptr)
            {
                // インスタンスを生成します。
                instance = gcnew QueueUtil(capacity);
            }
            return instance;
        }

        /// <summary>
        /// メッセージをキューに設定します。
        ///
        /// param msg: メッセージ
        /// </summary>
        void SetMsg(String^ msg)
        {
            // イベントとキューが有効な場合
            // 念のためのチェック
            if ((event != nullptr) && (queue != nullptr))
            {
                // キューをロックします。
                Monitor::Enter(queue);

                // キューにメッセージを設定します。
                queue->Enqueue(msg);

                // イベントをセットします。
                event->Set();

                // キューのロックを解除します。
                Monitor::Exit(queue);
            }
        }

        /// <summary>
        /// メッセージがキューに設定されるのを待ちます。
        ///
        /// return: メッセージ
        /// </summary>
        String^ WaitMsg()
        {
            // イベント待ち。
            event->WaitOne();

            // キューをロックします。
            Monitor::Enter(queue);

            // キューにメッセージが設定されている場合
            String^ msg = String::Empty;
            if (queue->Count > 0)
            {
                // キューからメッセージを取得します。
                msg = (String^)(queue->Dequeue());

                // キュー設定されたメッセージ分処理するため、
                // キューが空になってからイベント待ち状態にします。
                if (queue->Count == 0)
                {
                    // イベント待ち状態に設定します。
                    event->Reset();
                }
            }

            // キューにメッセージが設定されていない場合
            // 念のための処理
            else
            {
                // イベント待ち状態に設定します。
                event->Reset();
            }

            // キューのロックを解除します。
            Monitor::Exit(queue);

            return msg;
        }
    };
}

API Reference
Queueクラス
ManualResetEventクラス
Monitorクラス

目次へ

3. おわりに

例によって、C++/CLIに詳しい同僚に教えてもらいました。
こういったロジックを覚えるのはいつも楽しいです。

知識・スキルの販売サイト【ココナラ】

Visual C++ 2005 実用サンプルプログラム WindowsプログラミングTips108

Visual C++ 2005 実用サンプルプログラム WindowsプログラミングTips108

紹介している一部の記事のコードはGitlabで公開しています。
興味のある方は覗いてみてください。

目次へ


私が勤務しているニューラルでは、主に組み込み系ソフトの開発を行っております。
弊社製品のハイブリッドOS Bi-OSは高い技術力を評価されており、特に制御系や通信系を得意としています。
私自身はiOSモバイルアプリウィンドウズアプリを得意としております。
ソフトウェア開発に関して相談などございましたら、お気軽にご連絡ください。

また一緒に働きたい技術者の方も随時募集中です。
興味がありましたらご連絡ください。

EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688

目次へ