質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2913閲覧

C++で受信クラスと受信内容に対するアクションを分ける実装方法?

sin_250

総合スコア112

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/05/13 12:51

編集2017/05/13 12:56

以下のコードの通り、一応の解決案は持っているのですが、
よりシンプルな案はないかと思ったので質問させていただきます。

以下のような条件をお考えください。
・ある機械がある
・その機械は何らかの通信をし、通信データを受信する受信部を持っている
・機械は、受信内容に合わせて何かしらのアクションを取る

そこで以下のようにクラスを実装したいです。
・機械のためのMachineクラスを作る
・受信部のためのReceiverクラスを作る
・MachineクラスはReceiverクラスをメンバとして所有する
・Receiverクラスはstart()メソッドを持ち、その中で延々と受信ループを回す
・Receiverは受信だけに専念し、Machineが受信内容に対してどういうアクションを取るかは関知しない

このとき、Receiverが受信ループの中で受信した内容を、Machineクラスにどうやって伝え、
そしてMachineクラスの受信内容に対するアクションの実装は、どのようにしたらよいでしょうか。
Receiverクラスは受信だけに専念するクラスなので、そもそもMachineクラスの存在など知りません。

私の一つの解決案?は以下ですが、もっと少し簡単な方法があれば知りたいです。

cpp

1#include <iostream> 2#include <unistd.h> 3#include <string> 4 5class ReceiveHandler { // 受信ハンドラインターフェース 6public: 7 virtual void onReceive(std::string msg) = 0; 8}; 9 10class Receiver { 11private: 12 ReceiveHandler* handler_; 13public: 14 void setReceiveHandler(ReceiveHandler* handler) { 15 handler_ = handler; 16 } 17 void start() { 18 while(true) { // 受信ループ 19 std::string msg = "hoge"; // 本当は msg = wait_receive() みたいな感じ 20 handler_->onReceive(msg); 21 sleep(1); // 本当は要らない 22 } 23 } 24}; 25 26class Machine : ReceiveHandler { // Machine自信が受信ハンドラインターフェースになる 27private: 28 Receiver receiver_; 29public: 30 Machine() { 31 receiver_.setReceiveHandler(this); // 自分自身を受信ハンドラとしてセット 32 } 33 void onReceive(std::string msg) { 34 std::cout << "Message Received: " << msg << std::endl; 35 } 36 void startReceive() { 37 receiver_.start(); 38 } 39}; 40 41int main(void) { 42 Machine machine; 43 machine.startReceive(); 44 45 return 0; 46} 47 48

これを実行すると、1秒おきに
Message Received: hoge
が表示されます。

これが普通のやり方なのか、もっと簡単な方法があるのか、気になっております。
なお受信メッセージをReceiver.start()内でキューイングして、Machine側でキューをポーリングして取り出す、というのは
あまり考えておりません。リアルタイム性が怪しくなるためです。
あくまで、受信したら受信内容に対するアクションを即時に起こさせたいです。

アドバイスいただきたく、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

もし、受信→機械動作→受信→機械動作 というように完全にシリーズに実行されるのであれば、その実装でも悪くはないような気がします。
ただ、MachineがReceiverのインスタンスを保持し、かつ、ReceiverがMachineへのポインタを保持する点が、相互参照になるため心配です。相互参照は必要でない場合は避けた方が安全です。

なお、一般に通信と機械動作は平行に行うケースも多いと思います。
その場合は、それぞれのメイン・ループを別スレッドにすると制御ロジックを単純化できます。その時はReceiverを外に出して相互参照を回避しておかないと、デッドロックしやすくなると思います。

また、外部からの要求をReceiverが受け付けると言う構成であれば、Receiverは理論的にMachineに対するマスターになります。その場合はReceiverはMachineに依存させ、逆にMachineはReceiverに依存しない方が、経験的には機能拡張に耐えやすくなりそうな印象も受けます。

投稿2017/05/13 13:53

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2017/05/13 14:06

早速のコメントありがとうございます。理解力が浅く恐縮ですが、もう少し詳細をお尋ねしてよいでしょうか。 >相互参照は必要でない場合は避けた方が安全です。 おっしゃるとおりだと思います。私もその点が気になっていました。これが気持ち悪いので、もう少しシンプルなコードはないかなと思っています。 >その場合はReceiverはMachineに依存させ、逆にMachineはReceiverに依存しない方が おっしゃるように今はReceiverクラスが直接、外部との通信をする、例えばソケットを張ることを考えています。 これは、ReceiverがMachineのインスタンスを所有するという意味でしょうか?例えば以下のような感じです。 class Receiver { private: Machine machine_; public: void start() { msg = wait_receive(); machine_.doAction(msg); } }; >それぞれのメイン・ループを別スレッドにすると制御ロジックを単純化 この場合、Receiverクラスで新たなメッセージを受信した時、即時にMachineクラス側にメッセージを通知する方法はあるのでしょうか?(浅学で恐縮ですが、マルチスレッドプログラミングの経験が少なく、イメージを持てていません) 質問多く恐縮です。何卒よろしくお願いいたします。
Chironian

2017/05/13 15:09

> これは、ReceiverがMachineのインスタンスを所有するという意味でしょうか? ReceiverがMachineを所有しても良いとは思いますが、通信回線が機械を所有するイメージはちょっと違うかなと感じます。 この辺は、現実のモデルに近い実装を採用しておいた方が、変更に耐えやすいです。(現実世界の変更は物理法則の制約を受けますから、現実に近いモデルの方が現実の変更を受け入れやすい筈) リアルでも通信回線の部品と機械部分は独立していて、同じ筐体内に収めている場合が多いと思います。 それと同じように、ReceiverとMachineを統括する例えばHousingのようなクラスがあると良いかも知れません。 HousingがReceiverとMachineのインスタンスを保持し、その間の接続を担うイメージです。 例えば、Machineをコンストラクトしてその参照をReceiverのコンストラクタへ渡す等ですね。 もし、Machineが多種類ある場合は、インタフェース用の基底クラス(ReceiveHandlerみたいなもの)を定義して独立化することも考えられますが、インタフェースを追加する時の手間がかかる割に、実際に複数のマシン・クラスを別途定義するよりは、単に変数を追加して動作を切り替える方がありがちな気がします。ハードウェアはソフトウェアに比べると遥かに変更がたいへんなので、別クラスが必要になるほどの大変更はなかなかないものです。 マルチ・スレッドをどうするかはたいへん悩ましいです。 まず、スレッド間でどのような通信が必要になるのかを決める必要があります。 恐らく、ReceiverからMachineに対して要求があり、逆方向に応答があると思います。 これらがどのように発生するのかにより、大きく実装は変わります。 要求A→応答A→要求B→応答Bのように単純なケースなら要求イベントと応答イベントを使う程度で済みます。 機械が動作している間、時々動作状況の通知があり、その合間に要求と応答が発生する場合もあるでしょう。更に、要求が頻発するためキューにいれないと行けないかも知れません。もしくは、頻発しすぎても処理できないので、ダブルバッファにするかも知れません。 次に、マルチ・スレッドをどのように構成するべきかについては、私も確定した方針を持っていません。臨機応変と言うとかっこいいですが、どちらかと言うと行き当たりばったりかも知れません。
sin_250

2017/05/16 13:24

詳細なご回答ありがとうございます。おかげさまで、それなりにわかってきました。 よい設計というのは、難しいですね。がんばります。 ご回答有り難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問