コンピュータ将棋ソフトとの対局サーバーを立てよう＜その１２＞

前回の記事 : http://qiita.com/muzudho1/items/3d292bafc4a8fa54eb43

# cppをバックグラウンドで走らせて

フォアグラウンドで cpp を叩く。


```
# cd ../csharp_service
# ./tamesi35a2_cs.exe

Unhandled Exception:
System.Exception: コマンドライン引数に「--msgqueue キュー名 寿命 キュー名 寿命」を指定しろだぜ☆（＾～＾）
エンキュー先、デキュー先の順番な☆（＾▽＾）
寿命は durable, autodelete, passive, exclusive のいずれかで、
複合指定にはまだ対応していないぜ☆（＞＿＜）
  at Program.Main (System.String[] args) <0x40857270 + 0x0041f> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Exception: コマンドライン引数に「--msgqueue キュー名 寿命 キュー名 寿命」を指定しろだぜ☆（＾～＾）
エンキュー先、デキュー先の順番な☆（＾▽＾）
寿命は durable, autodelete, passive, exclusive のいずれかで、
複合指定にはまだ対応していないぜ☆（＞＿＜）
  at Program.Main (System.String[] args) <0x40857270 + 0x0041f> in <filename unknown>:0
```

起動してすぐに落ちた。

tamesi35a2_cs.exe ではなく、tamesi34_cs.exe を起動したいのだった。

```
# jobs
[1]+  Running                 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &  (wd: /home/★user/shogi/cpp_service)
```

Job はまだ生きている。

```
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[True]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1117]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? >
```

- Windows10 / RabbitMQ では durable
- Ubuntu16.04 / RabbitMQ では durable + autodelete

が初期設定になっている現環境実装なことは前回の記事で調べた。

```
Enqueue? > usi
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[True]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1116]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定

Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x403b9410 + 0x00107> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x403b7290 + 0x000fd> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x403bc340 + 0x00113> in <filename unknown>:0
  at UsagiMQ.Program.GetChannel (Int32 index) <0x4037cd10 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x403bd420 + 0x00013> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x40377d50 + 0x009a7> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x403b9410 + 0x00107> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x403b7290 + 0x000fd> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x403bc340 + 0x00113> in <filename unknown>:0
  at UsagiMQ.Program.GetChannel (Int32 index) <0x4037cd10 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x403bd420 + 0x00013> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x40377d50 + 0x009a7> in <filename unknown>:0
```

**すると、コンシューマーは durable+autodelete だが、プロデューサーは urable だけなのだろうか？**

./tamesi34_cs.exe の設定プロンプトでプロデューサーの寿命は 3 ではなく 1 に変えよう。

```
# jobs
[1]+  Running                 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &  (wd: /home/★user/shogi/cpp_service)
```

バックグラウンド・プロセスはまだ生きている。

```
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1117]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > usi
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1116]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [False]
    nowait は仮に false 固定
    arguments は仮に null 固定
 Enqueue(^q^) usi
Enqueue? >
```

usi はエンキューできたが、応答がこない。 tamesi35a2_cpp.exe が落ちたのだろうか？

[Ctrl] + [C]

```
[1]+  Aborted                 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log  (wd: /home/★user/shogi/cpp_service)
(wd now: /home/★user/shogi/csharp_service)
```

アボート（強制終了）している。

```
# nano tamesi35a2_cpp.err.log
```

```
tamesi35a2_cpp.exe: ev.c:3541: ev_run: Assertion `("libev: ev_loop recursion during release detected", ((loop)->loop_done) != 0x80)' failed.
```

前回の記事の知見で改造する。

- シングルトン
- スレッド
- プロデューサーは durable、コンシューマーは durable+autodelete

この２つで。

# まずシングルトンにしよう

おっと、その前に tamesi35a2_cpp.cpp を複数寿命指定に対応させたい。

tamesi35a2_cpp.cpp

```cpp
//--------------------------------------------------------------------------------
// OS      : Windows10 : // このプログラムは動かない
//
// OS      : Ubuntu 16.04
// Library : libev
//         : Install   : Command  : sudo apt-get update
//                                : sudo apt-get install libev-dev
// Service : RabbitMQ
//         : Reference : Web site : Top page http://www.rabbitmq.com/
//         : Install   : Web site : Installing on Debian / Ubuntu http://www.rabbitmq.com/install-debian.html
//         : Manual    : Command  : man rabbitmqctl
//         : Start     : Command  : rabbitmq-server
//         : Stop      : Command  : rabbitmqctl stop
//         : Check     : Command  : rabbitmqctl status
//         :           : Command  : rabbitmqctl list_queues
// Library : AMQP-CPP
//         : Reference : Web site : AMQP-CPP README.md https://github.com/CopernicaMarketingSoftware/AMQP-CPP
//         : Reference : Web site : QueueDeclare http://docs.spring.io/spring-amqp-net/docs/1.0.x/api/html/Spring.Messaging.Amqp.Rabbit~Spring.Messaging.Amqp.Rabbit.Connection.CachedModel~QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary).html
//         : Reference : Web site : EventingBasicConsumer https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.Events.EventingBasicConsumer.html
//         : Reference : Web site : BasicConsume https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IModel.html#method-M:RabbitMQ.Client.IModel.BasicConsume(System.UInt16,System.String,System.Boolean,System.Collections.IDictionary,RabbitMQ.Client.IBasicConsumer)
//         : Reference : Web site : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
//         : Reference : Web site : AMQP-CPP (docsforge.com) http://docsforge.com/11/AMQP-CPP/docs/latest/namespace-AMQP/class-TcpConnection/
//
// Program : this
//         : Compile   : Command  : g++ -std=c++11 tamesi35a2_cpp.cpp -o tamesi35a2_cpp.exe -lev -lamqpcpp -pthread
//         : Execute   : Command  : // バックグラウンドで実行
//                                : ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log &
//         : Stop      : Typing   : [Ctrl]+[C]
//--------------------------------------------------------------------------------
//
// メッセージの末尾に daze を付けます。
// デキューは「1112」、エンキューは「1113」キューに向けて行います。
// 標準入出力は、キーボード、画面には接続しないようにします。

#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
#include <chrono>
#include <thread> // sleep_for
#include <future> // thread

// プロセス間通信用
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>

// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
enum LifeSpanType
{
	// RabbitMQが止まってもキューを残す
	durable = 1,
	// コンシューマーが１人も接続していなかったら消す
	autodelete = 0x1 << 1,
	// キューが存在するかどうかチェックするだけ。中身見ない時これ
	passive = 0x1 << 2,
	// この接続でだけ使える。この接続が切れたら消す
	exclusive = 0x1 << 3
};

static AMQP::Address ADDRESS{ "amqp://localhost:5672" };
// 0 : enqueue用設定
// 1 : dequeue用設定
static const int ENQUEUE_INDEX = 0;
static const int DEQUEUE_INDEX = 1;
static const int NUM_INDEX = 2;
static std::string name_queues[] = { "1117", "1116" };
static LifeSpanType lifeSpan_queues[] = { (LifeSpanType)0, (LifeSpanType)0 };
static LifeSpanType LifeSpanString_To_Enum(std::string lifeSpan)
{
	if ("durable"==lifeSpan) {
		return durable;
	} else if ("autodelete" == lifeSpan) {
		return autodelete;
	} else if ("passive" == lifeSpan) {
		return passive;
	} else if ("exclusive" == lifeSpan) {
		return exclusive;
	} else {
		std::cerr << "未対応のlifeSpan [" << lifeSpan << "]";
		exit(1);
	}
}
static int LifeSpanString_To_AmqpInt(LifeSpanType lifeSpan)
{
	if (durable == lifeSpan) {
		return AMQP::durable;
	}
	else if (autodelete == lifeSpan) {
		return AMQP::autodelete;
	}
	else if (passive == lifeSpan) {
		return AMQP::passive;
	}
	else if (exclusive == lifeSpan) {
		return AMQP::exclusive;
	}
	else {
		std::cerr << "未対応のlifeSpan [" << lifeSpan << "]";
		exit(1);
	}
}

static std::string Dump()
{
	static std::ostringstream sb;
	sb << "tamesi35a2_cs.cs Dump" << std::endl
		<< "    name_queues         [ENQUEUE_INDEX]    =[" << name_queues[ENQUEUE_INDEX] << "]"
		<< "    lifeSpan_queues     [ENQUEUE_INDEX]    =[" << lifeSpan_queues[ENQUEUE_INDEX] << "]"
		<< "    ----"
		<< "    name_queues         [DEQUEUE_INDEX]    =[" << name_queues[DEQUEUE_INDEX] << "]"
		<< "    lifeSpan_queues     [DEQUEUE_INDEX]    =[" << lifeSpan_queues[DEQUEUE_INDEX] << "]"
		<< "    ----";
	return sb.str();
}

// 接続はシングルトンにします
//auto* loop = EV_DEFAULT;
//struct ev_loop** loop_queues = { EV_DEFAULT, EV_DEFAULT };


/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
namespace rotationBuffer
{
	const int bufferSize = 100;
	static std::string buffer[bufferSize] = {};
	static int bufferCursors[2] = { 0, 0 };
	const int PUT_INDEX = 0;
	const int GET_INDEX = 1;

	std::mutex _mutex;
	static void putMessage(std::string message)
	{
		std::unique_lock<std::mutex> lock(_mutex);
		buffer[bufferCursors[PUT_INDEX]] = message;
		bufferCursors[PUT_INDEX]++;
		if (!(bufferCursors[PUT_INDEX] < bufferSize))
		{
			bufferCursors[PUT_INDEX] = 0;
		}
	}
	static std::string getMessage()
	{
		std::unique_lock<std::mutex> lock(_mutex);
		if ("" != buffer[bufferCursors[GET_INDEX]])
		{
			std::string message = buffer[bufferCursors[GET_INDEX]];
			buffer[bufferCursors[GET_INDEX]] = "";
			bufferCursors[GET_INDEX]++;
			if (!(bufferCursors[GET_INDEX] < bufferSize))
			{
				bufferCursors[GET_INDEX] = 0;
			}
			return message;
		}
		return "";
	}
}

// メッセージキューにエンキュー
static void enqueue(std::string message)
{
	// エンキュー用の接続
	struct ev_loop* loop;
	AMQP::LibEvHandler handler{ loop };
	//AMQP::LibEvHandler handler{ loop_queues[ENQUEUE_INDEX] };
	AMQP::TcpConnection connection{ &handler, ADDRESS };
	AMQP::TcpChannel channel{ &connection };

	std::string exchange_name = "myexchange";
	std::string routing_key = "";

	int lifeSpan = LifeSpanString_To_AmqpInt(lifeSpan_queues[ENQUEUE_INDEX]);

	channel.declareQueue(name_queues[ENQUEUE_INDEX], lifeSpan)
		.onError([&lifeSpan](const char* errMsg) {
		std::cerr << "error declaring queue: " << errMsg << " lifeSpan=[" << lifeSpan << "]" << "\n";
	});

	channel.bindQueue(exchange_name, name_queues[ENQUEUE_INDEX], routing_key)
		.onSuccess([&connection, &channel, &exchange_name, &routing_key, &message]() {

		if (!channel.publish(exchange_name, routing_key, message.c_str(), message.size())) {
			std::cerr << "failed to publish?\n";
		}

		// break in ev loop.
		connection.close();
	});

	// このループは、パブリッシュ後に抜ける
	ev_run(loop);
	//ev_run(loop_queues[ENQUEUE_INDEX]);
}

// 受信できたときに割り込んでくる処理
// startConsume() しておくこと。
static std::string dequeue() {
	std::string message;

	while ("" == message)
	{
		message = rotationBuffer::getMessage();
	}

	return message;
}

//// メッセージ・キューの送信を担当
//static void workProduce()
//{
//
//}

// メッセージ・キューの監視を開始
static void workConsume()
{
	// Connect to the AMQP service.
	struct ev_loop* loop;
	AMQP::LibEvHandler handler{ loop };
	//AMQP::LibEvHandler handler(loop_queues[DEQUEUE_INDEX]);
	AMQP::TcpConnection connection(&handler, ADDRESS);
	AMQP::TcpChannel channel(&connection);

	// I will go to the front of the box named "1111".
	int lifeSpan = LifeSpanString_To_AmqpInt(lifeSpan_queues[DEQUEUE_INDEX]);
	channel.declareQueue(name_queues[DEQUEUE_INDEX], lifeSpan);

	// I look inside the box.
	auto errorCb = [&lifeSpan](const char *errMsg) {
		std::cerr << "My ID watching failed [" << errMsg << "] lifeSpan=[" << lifeSpan << "]" << std::endl;
	};
	auto messageCb = [&channel](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {

		std::string myString(message.body(), message.bodySize());
		rotationBuffer::putMessage(myString);

		channel.ack(deliveryTag);
	};
	channel.consume(name_queues[DEQUEUE_INDEX])
		.onReceived(messageCb)
		.onError(errorCb);

	// I will keep on forever.
	ev_run(loop);
	//ev_run(loop_queues[DEQUEUE_INDEX], 0);

	// I will not come here.
	return;
}

int main(int argc, char* argv[])
{
	std::cout << "Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]) + " ";
		}
		std::istringstream data(cmdArg);

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string titles[2]; // 結果はこれらの配列に入れる
		std::vector<std::vector<std::string>> lifespans;

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (!data.eof()) {
			data >> a;
			if ("--enqueue" == a.substr(0, 2))
			{
				m0 = 0;
				titles[m0] = a.substr(2); // 最初の２文字「--」の次から
				lifespans.push_back(std::vector<std::string>()); // リストの中にリストを準備
			}
			else if ("--dequeue" == a.substr(0, 2))
			{
				m0 = 1;
				titles[m0] = a.substr(2); // 最初の２文字「--」の次から
				lifespans.push_back(std::vector<std::string>()); // リストの中にリストを準備
			}
			else { lifespans[m0].push_back(a); } // 要素数-1 で最後の要素

			std::cout << "a=[" << a << "]" << std::endl;
		}

		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = titles[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = titles[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();
	return 0;
}
```

```
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1117]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > usi
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1116]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1117]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1116]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [False]
    nowait は仮に false 固定
    arguments は仮に null 固定
 Enqueue(^q^) usi
Enqueue? >
```

動かね。落ちてるし。もっかい起動。

```
root@tk2-217-18401:/home/★user/shogi/cpp_service# Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
jobs
[1]+  Segmentation fault      ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log
```

セグメンテーション・フォールトって何だぜ？

「Running application ends with “Segmentation Fault”」（UNIX & LINUX）
http://unix.stackexchange.com/questions/132192/running-application-ends-with-segmentation-fault

プログラムをコメントアウトしても　これが出る。

```
# ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log &
```

```
# ./tamesi35a2_cpp.exe
```

こうすると　違うプログラムの結果が出るんだが。

```
                // 解析器
                std::string a;
                while (!data.eof()) {
                        data >> a;
                        if ("--enqueue" == a.substr(0, 2))
                        {
                                m0 = 0;
                                titles[m0] = a.substr(2); // 最初の２文字「--」の次から
                                lifespans.push_back(std::vector<std::string>()); // リストの中にリストを準備
                        }
                        else if ("--dequeue" == a.substr(0, 2))
                        {
                                m0 = 1;
                                titles[m0] = a.substr(2); // 最初の２文字「--」の次から
                                lifespans.push_back(std::vector<std::string>()); // リストの中にリストを準備
                        }
                        else { lifespans[m0].push_back(a); } // 要素数-1 で最後の要素

                        std::cout << "a=[" << a << "]" << std::endl;
                }
```

この直前まで動く。この中で　セグメンテーション・フォールトしてるようだ。

あー。

```
# ./tamesi35a2_cpp.exe
```

引数付けずに　コマンド叩いていたぜ。

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]) + " ";
		}
		std::istringstream data(cmdArg);

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (!data.eof()) {
			data >> a;
			std::cout << "a=[" << a << "]" << std::endl;

			if (2<a.size() && "--enqueue" == a.substr(0, 2))
			{
				m0 = 0;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else if (2<a.size() && "--dequeue" == a.substr(0, 2))
			{
				m0 = 1;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else { lifespans[m0].push_back(a); } // 要素数-1 で最後の要素
		}

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

こう書いてもまだ　セグメンテーション・フォールト。

じゃあ、こうか。

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]) + " ";
		}
		std::istringstream data(cmdArg);

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (!data.eof()) {
			data >> a;
			std::cout << "a=[" << a << "]" << std::endl;

			if (2<a.size() && "--enqueue" == a.substr(0, 2))
			{
				m0 = 0;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else if (2<a.size() && "--dequeue" == a.substr(0, 2))
			{
				m0 = 1;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else { lifespans[m0].push_back(a); } // 要素数-1 で最後の要素
		}

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

```
# ./tamesi35a2_cpp.exe
(^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
a=[]
コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete
```

これで警告を出しておこう。

```
# ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable35a2_cpp.err.log &amesi
[1] 16535
root@tk2-217-18401:/home/★user/shogi/cpp_service# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
a=[--enqueue]
a=[1117]
a=[durable]
a=[autodelete]
a=[--dequeue]
a=[1116]
a=[durable]
a=[autodelete]
a=[autodelete]
```

最後の２つが余計だな。

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]) + " ";
		}
		std::cout << "(^q^)Welcome! cmdArg=[" << cmdArg << "]" << std::endl;
		std::istringstream data(cmdArg);

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (!data.eof()) {
			data >> a;
			std::cout << "a=[" << a << "]" << std::endl;

			if ("--enqueue" == a)
			{
				std::cout << "(^q^)A!" << std::endl;
				m0 = 0;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else if ("--dequeue" == a)
			{
				std::cout << "(^q^)B!" << std::endl;
				m0 = 1;

				data >> a;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else
			{
				std::cout << "(^q^)C!" << std::endl;
				lifespans[m0].push_back(a);
			} // 要素数-1 で最後の要素
		}

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

プログラム間違えてる。

```
root@tk2-217-18401:/home/★user/shogi/cpp_service# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)Welcome! cmdArg=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]
a=[--enqueue]
(^q^)A!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
a=[--dequeue]
(^q^)B!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
a=[autodelete]
(^q^)C!
*** Error in `./tamesi35a2_cpp.exe': realloc(): invalid next size: 0x00007f49678d6e60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f496736d7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82a5a)[0x7f4967378a5a]
/lib/x86_64-linux-gnu/libc.so.6(+0x84ff9)[0x7f496737aff9]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f4967379d3f]
/usr/lib/x86_64-linux-gnu/libev.so.4(+0x3f2a)[0x7f49681d2f2a]
/usr/lib/x86_64-linux-gnu/libev.so.4(ev_io_start+0x10d)[0x7f49681d430d]
./tamesi35a2_cpp.exe[0x4206a5]
./tamesi35a2_cpp.exe[0x42081f]
/usr/lib/libamqpcpp.so.2.6(_ZN4AMQP11TcpResolverC1EPNS_13TcpConnectionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEtPNS_10TcpHandlerE+0x113)[0x7f4967f90869]
/usr/lib/libamqpcpp.so.2.6(_ZN4AMQP13TcpConnectionC1EPNS_10TcpHandlerERKNS_7AddressE+0xa2)[0x7f4967f8e09c]
./tamesi35a2_cpp.exe[0x41ba70]
./tamesi35a2_cpp.exe[0x41bc47]
./tamesi35a2_cpp.exe[0x41e654]
./tamesi35a2_cpp.exe[0x41e5aa]
./tamesi35a2_cpp.exe[0x41e53a]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xb8c80)[0x7f4967baac80]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x76ba)[0x7f49676c66ba]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7f49673fc82d]
======= Memory map: ========
00400000-00433000 r-xp 00000000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00633000-00634000 r--p 00033000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00634000-00635000 rw-p 00034000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00635000-00636000 rw-p 00000000 00:00 0
0113b000-0116d000 rw-p 00000000 00:00 0                                  [heap]
7f4960000000-7f4960021000 rw-p 00000000 00:00 0
7f4960021000-7f4964000000 ---p 00000000 00:00 0
7f49667ec000-7f49667ed000 ---p 00000000 00:00 0
7f49667ed000-7f4966fed000 rw-p 00000000 00:00 0                          [stack:16631]
7f4966fed000-7f49670f5000 r-xp 00000000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7f49670f5000-7f49672f4000 ---p 00108000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7f49672f4000-7f49672f5000 r--p 00107000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7f49672f5000-7f49672f6000 rw-p 00108000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7f49672f6000-7f49674b5000 r-xp 00000000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7f49674b5000-7f49676b5000 ---p 001bf000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7f49676b5000-7f49676b9000 r--p 001bf000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7f49676b9000-7f49676bb000 rw-p 001c3000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7f49676bb000-7f49676bf000 rw-p 00000000 00:00 0
7f49676bf000-7f49676d7000 r-xp 00000000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7f49676d7000-7f49678d6000 ---p 00018000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7f49678d6000-7f49678d7000 r--p 00017000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7f49678d7000-7f49678d8000 rw-p 00018000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7f49678d8000-7f49678dc000 rw-p 00000000 00:00 0
7f49678dc000-7f49678f2000 r-xp 00000000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f49678f2000-7f4967af1000 ---p 00016000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f4967af1000-7f4967af2000 rw-p 00015000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f4967af2000-7f4967c64000 r-xp 00000000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f4967c64000-7f4967e64000 ---p 00172000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f4967e64000-7f4967e6e000 r--p 00172000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f4967e6e000-7f4967e70000 rw-p 0017c000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f4967e70000-7f4967e74000 rw-p 00000000 00:00 0
7f4967e74000-7f4967fc2000 r-xp 00000000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7f4967fc2000-7f49681c2000 ---p 0014e000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7f49681c2000-7f49681c8000 r--p 0014e000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7f49681c8000-7f49681cf000 rw-p 00154000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7f49681cf000-7f49681dc000 r-xp 00000000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7f49681dc000-7f49683db000 ---p 0000d000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7f49683db000-7f49683dc000 r--p 0000c000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7f49683dc000-7f49683dd000 rw-p 0000d000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7f49683dd000-7f4968403000 r-xp 00000000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7f49685ee000-7f49685f4000 rw-p 00000000 00:00 0
7f49685ff000-7f4968602000 rw-p 00000000 00:00 0
7f4968602000-7f4968603000 r--p 00025000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7f4968603000-7f4968604000 rw-p 00026000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7f4968604000-7f4968605000 rw-p 00000000 00:00 0
7ffc69d66000-7ffc69d87000 rw-p 00000000 00:00 0                          [stack]
7ffc69df6000-7ffc69df8000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
^C
[1]+  Aborted                 ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log
```

```cpp
		std::string a;
		while (!data.eof()) {
			a = "(^q^)error!";
			data >> a;
			std::cout << "a=[" << a << "]" << std::endl;
```

文字列の終端を取れていないようだ。

```
root@tk2-217-18401:~# ls
tamesi35a2_cs.err.log  tamesi35a2_cs.out.log
```

エラーログが、ルート・フォルダに吐かれてるんじゃないか？

```
# ./tamesi35a2_cpp.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log &
[1] 17059

# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)Welcome! cmdArg=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]
(^q^)Welcome! data.str()=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]
a=[--enqueue]
(^q^)A!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
a=[--dequeue]
(^q^)B!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
a=[(^q^)error! data.str()=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]]
(^q^)C!
```

最後の動きは何だろう？

「Why doesn't the istringstream eof flag become true when successfully converting a boolean string value to a bool?」（stack overflow）
http://stackoverflow.com/questions/24219807/why-doesnt-the-istringstream-eof-flag-become-true-when-successfully-converting

「!data.eof()」が g++ だと動いてないんじゃないか？

「std::istream::tellg」（cplusplus.com）
http://www.cplusplus.com/reference/istream/istream/tellg/

g++ だと「-1 != data.tellg()」もダメみたいだが。

浮かむ瀬を見習うと

```cpp
while (data >> a) {
```

でいいようだ。

```
# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)Welcome! cmdArg=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]
(^q^)Welcome! data.str()=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]
a=[(^q^)error! data.str()=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete ]]
(^q^)C!
```

うーむ？

```
# (^q^)Welcome! AMQP::durable=[1                    ] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete                     ]
(^q^)data.str()=[--enqueue 1117 durable autodelete --dequeue 1116 durable autode                    lete ]
a=[--enqueue]
(^q^)A!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
a=[--dequeue]
(^q^)B!
a=[durable]
(^q^)C!
a=[autodelete]
(^q^)C!
*** Error in `./tamesi35a2_cpp.exe': realloc(): invalid next size: 0x00007f6141d                    21e60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f61417b87e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82a5a)[0x7f61417c3a5a]
/lib/x86_64-linux-gnu/libc.so.6(+0x84ff9)[0x7f61417c5ff9]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f61417c4d3f]
/usr/lib/x86_64-linux-gnu/libev.so.4(+0x3f2a)[0x7f614261df2a]
```

うーむ？

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]) + " ";
		}
		std::cout << "(^q^)cmdArg=[" << cmdArg << "]" << std::endl;
		std::istringstream data(cmdArg);
		//data >> std::skipws;
		std::cout << "(^q^)data.str()=[" << data.str() << "]" << std::endl;

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (data >> a) {
			std::cout << "(^_^)a0=[" << a << "]" << std::endl;

			if ("--enqueue" == a)
			{
				std::cout << "(^q^)A!" << std::endl;
				m0 = 0;

				if (!(data >> a)) {
					break;
				}
				std::cout << "(^_^)a1=[" << a << "]" << std::endl;

				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else if ("--dequeue" == a)
			{
				std::cout << "(^q^)B!" << std::endl;
				m0 = 1;

				if (!(data >> a)) {
					break;
				}
				std::cout << "(^_^)a2=[" << a << "]" << std::endl;

				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else
			{
				std::cout << "(^q^)C!" << std::endl;
				lifespans[m0].push_back(a);
			} // 要素数-1 で最後の要素
		}

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

こう書いて、

```
# ./tamesi35a2_cpp.exe --enqueue 1117 durable --dequeue 1116 durable autodelete 2> ./tamesi35a2_cpp.err.log &
[1] 17696
root@tk2-217-18401:/home/★user/shogi/cpp_service# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^q^)data.str()=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^_^)a0=[--enqueue]
(^q^)A!
(^_^)a1=[1117]
(^_^)a0=[durable]
(^q^)C!
(^_^)a0=[--dequeue]
(^q^)B!
(^_^)a2=[1116]
(^_^)a0=[durable]
(^q^)C!
(^_^)a0=[autodelete]
(^q^)C!
*** Error in `./tamesi35a2_cpp.exe': realloc(): invalid next size: 0x00007fcd66751e60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fcd661e87e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82a5a)[0x7fcd661f3a5a]
/lib/x86_64-linux-gnu/libc.so.6(+0x84ff9)[0x7fcd661f5ff9]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7fcd661f4d3f]
/usr/lib/x86_64-linux-gnu/libev.so.4(+0x3f2a)[0x7fcd6704df2a]
/usr/lib/x86_64-linux-gnu/libev.so.4(ev_io_start+0x10d)[0x7fcd6704f30d]
./tamesi35a2_cpp.exe[0x4208cf]
./tamesi35a2_cpp.exe[0x420a49]
/usr/lib/libamqpcpp.so.2.6(_ZN4AMQP11TcpResolverC1EPNS_13TcpConnectionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEtPNS_10TcpHandlerE+0x113)[0x7fcd66e0b869]
/usr/lib/libamqpcpp.so.2.6(_ZN4AMQP13TcpConnectionC1EPNS_10TcpHandlerERKNS_7AddressE+0xa2)[0x7fcd66e0909c]
./tamesi35a2_cpp.exe[0x41bb60]
./tamesi35a2_cpp.exe[0x41bd37]
./tamesi35a2_cpp.exe[0x41e87e]
./tamesi35a2_cpp.exe[0x41e7d4]
./tamesi35a2_cpp.exe[0x41e764]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xb8c80)[0x7fcd66a25c80]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x76ba)[0x7fcd665416ba]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7fcd6627782d]
======= Memory map: ========
00400000-00434000 r-xp 00000000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00633000-00634000 r--p 00033000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00634000-00635000 rw-p 00034000 fd:01 1573709                            /home/★user/shogi/cpp_service/tamesi35a2_cpp.exe
00635000-00636000 rw-p 00000000 00:00 0
0089e000-008d0000 rw-p 00000000 00:00 0                                  [heap]
7fcd60000000-7fcd60021000 rw-p 00000000 00:00 0
7fcd60021000-7fcd64000000 ---p 00000000 00:00 0
7fcd65667000-7fcd65668000 ---p 00000000 00:00 0
7fcd65668000-7fcd65e68000 rw-p 00000000 00:00 0                          [stack:17697]
7fcd65e68000-7fcd65f70000 r-xp 00000000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7fcd65f70000-7fcd6616f000 ---p 00108000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7fcd6616f000-7fcd66170000 r--p 00107000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7fcd66170000-7fcd66171000 rw-p 00108000 fd:01 787800                     /lib/x86_64-linux-gnu/libm-2.23.so
7fcd66171000-7fcd66330000 r-xp 00000000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7fcd66330000-7fcd66530000 ---p 001bf000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7fcd66530000-7fcd66534000 r--p 001bf000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7fcd66534000-7fcd66536000 rw-p 001c3000 fd:01 787795                     /lib/x86_64-linux-gnu/libc-2.23.so
7fcd66536000-7fcd6653a000 rw-p 00000000 00:00 0
7fcd6653a000-7fcd66552000 r-xp 00000000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7fcd66552000-7fcd66751000 ---p 00018000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7fcd66751000-7fcd66752000 r--p 00017000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7fcd66752000-7fcd66753000 rw-p 00018000 fd:01 787801                     /lib/x86_64-linux-gnu/libpthread-2.23.so
7fcd66753000-7fcd66757000 rw-p 00000000 00:00 0
7fcd66757000-7fcd6676d000 r-xp 00000000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fcd6676d000-7fcd6696c000 ---p 00016000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fcd6696c000-7fcd6696d000 rw-p 00015000 fd:01 786610                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fcd6696d000-7fcd66adf000 r-xp 00000000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fcd66adf000-7fcd66cdf000 ---p 00172000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fcd66cdf000-7fcd66ce9000 r--p 00172000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fcd66ce9000-7fcd66ceb000 rw-p 0017c000 fd:01 1050075                    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fcd66ceb000-7fcd66cef000 rw-p 00000000 00:00 0
7fcd66cef000-7fcd66e3d000 r-xp 00000000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7fcd66e3d000-7fcd6703d000 ---p 0014e000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7fcd6703d000-7fcd67043000 r--p 0014e000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7fcd67043000-7fcd6704a000 rw-p 00154000 fd:01 1063316                    /usr/lib/libamqpcpp.so.2.6.2
7fcd6704a000-7fcd67057000 r-xp 00000000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7fcd67057000-7fcd67256000 ---p 0000d000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7fcd67256000-7fcd67257000 r--p 0000c000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7fcd67257000-7fcd67258000 rw-p 0000d000 fd:01 1063327                    /usr/lib/x86_64-linux-gnu/libev.so.4.0.0
7fcd67258000-7fcd6727e000 r-xp 00000000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7fcd67469000-7fcd6746f000 rw-p 00000000 00:00 0
7fcd6747a000-7fcd6747d000 rw-p 00000000 00:00 0
7fcd6747d000-7fcd6747e000 r--p 00025000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7fcd6747e000-7fcd6747f000 rw-p 00026000 fd:01 787782                     /lib/x86_64-linux-gnu/ld-2.23.so
7fcd6747f000-7fcd67480000 rw-p 00000000 00:00 0
7ffcd3118000-7ffcd3139000 rw-p 00000000 00:00 0                          [stack]
7ffcd31cb000-7ffcd31cd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]c
```

スペース区切りなので、最後のスペースの後ろに　ヌルでもあるんだろうか？

```
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]);
			if (i < argc) {
				cmdArg += " ";
			}
		}
```

こう書き直してどうか？

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]);
			if (i < argc) {
				cmdArg += " ";
			}
		}
		std::cout << "(^q^)cmdArg=[" << cmdArg << "]" << std::endl;
		std::istringstream data(cmdArg);
		//data >> std::skipws;
		std::cout << "(^q^)data.str()=[" << data.str() << "]" << std::endl;

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue

		// 解析器
		std::string a;
		while (data >> a) {
			std::cout << "(^_^)a0=[" << a << "]" << std::endl;

			if ("--enqueue" == a)
			{
				std::cout << "(^q^)A!" << std::endl;
				m0 = 0;

				if (!(data >> a)) {
					break;
				}
				std::cout << "(^_^)a1=[" << a << "] m0=[" << m0 << "]" << std::endl;

				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else if ("--dequeue" == a)
			{
				std::cout << "(^q^)B!" << std::endl;
				m0 = 1;

				if (!(data >> a)) {
					break;
				}
				std::cout << "(^_^)a2=[" << a << "] m0=[" << m0 << "]" << std::endl;

				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
			}
			else
			{
				std::cout << "(^q^)C1! m0=[" << m0 << "]" << std::endl;
				lifespans[m0].push_back(a);
				std::cout << "(^q^)C2!" << std::endl;
			} // 要素数-1 で最後の要素
		}

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

こうして、

```
# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^q^)data.str()=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^_^)a0=[--enqueue]
(^q^)A!
(^_^)a1=[1117] m0=[0]
(^_^)a0=[durable]
(^q^)C1! m0=[0]
(^q^)C2!
(^_^)a0=[--dequeue]
(^q^)B!
(^_^)a2=[1116] m0=[1]
(^_^)a0=[durable]
(^q^)C1! m0=[1]
(^q^)C2!
(^_^)a0=[autodelete]
(^q^)C1! m0=[1]
(^q^)C2!
*** Error in `./tamesi35a2_cpp.exe': realloc(): invalid next size: 0x00007fc090b98e60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fc09062f7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82a5a)[0x7fc09063aa5a]
/lib/x86_64-linux-gnu/libc.so.6(+0x84ff9)[0x7fc09063cff9]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7fc09063bd3f]
```

うーむ？

```
// 解析器
                std::string a;
                while (data >> a) {
                        std::cout << "(^_^)a0=[" << a << "]" << std::endl;
                }
                std::cout << "(^-^)Loop end." << std::endl;
```

こう書くと、

```
# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^q^)data.str()=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^_^)a0=[--enqueue]
(^_^)a0=[1117]
(^_^)a0=[durable]
(^_^)a0=[--dequeue]
(^_^)a0=[1116]
(^_^)a0=[durable]
(^_^)a0=[autodelete]
(^-^)Loop end.
```

```cpp
int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]);
			if (i < argc) {
				cmdArg += " ";
			}
		}
		std::cout << "(^q^)cmdArg=[" << cmdArg << "]" << std::endl;
		std::istringstream data(cmdArg);
		//data >> std::skipws;
		std::cout << "(^q^)data.str()=[" << data.str() << "]" << std::endl;

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue
		int m1 = -1; // lifespans index.

		// 解析器
		std::string a;
		while (data >> a) {
			std::cout << "(^_^)a0=[" << a << "]" << std::endl;

			if ("--enqueue" == a)
			{
				std::cout << "(^q^)A!" << std::endl;
				m0 = 0;
				m1 = -1;
			}
			else if ("--dequeue" == a)
			{
				std::cout << "(^q^)B!" << std::endl;
				m0 = 1;
				m1 = -1;
			}
			else if (-1 == m1 && 0 == m0) {
				std::cout << "(^q^)C!" << std::endl;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
				m1++;
			}
			else if (-1 == m1 && 1 == m0) {
				std::cout << "(^q^)D!" << std::endl;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
				m1++;
			}
			else
			{
				std::cout << "(^q^)E1! m0=[" << m0 << "] m1=[" << m1 << "]" << std::endl;
				lifespans[m0].push_back(a);
				std::cout << "(^q^)E2!" << std::endl;
			} // 要素数-1 で最後の要素
		}
		std::cout << "(^-^)Loop end." << std::endl;

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
			exit(1);
		}
		// エンキュー
		m0 = 0;
		name_queues[ENQUEUE_INDEX] = queueNames[m0];
		lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}
		m0 = 1;
		name_queues[DEQUEUE_INDEX] = queueNames[m0];
		{
			for (std::string lifespan : lifespans[m0])
			{
				lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
			}
		}

		Dump();
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

こう書くと　途中では落ちなくなったが。

```
# (^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^q^)data.str()=[--enqueue 1117 durable --dequeue 1116 durable autodelete ]
(^_^)a0=[--enqueue]
(^q^)エンキュー!
(^_^)a0=[1117]
(^q^)エンキューのキュー名!
(^_^)a0=[durable]
(^q^)寿命! m0=[0] m1=[0]
(^q^)zyumyo-!
(^_^)a0=[--dequeue]
(^q^)デキュー!
(^_^)a0=[1116]
(^q^)デキューのキュー名!
(^_^)a0=[durable]
(^q^)寿命! m0=[1] m1=[0]
(^q^)zyumyo-!
(^_^)a0=[autodelete]
(^q^)寿命! m0=[1] m1=[0]
(^q^)zyumyo-!
(^-^)Loop end.
*** Error in `./tamesi35a2_cpp.exe': realloc(): invalid next size: 0x00007f5984d78e60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f598480f7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82a5a)[0x7f598481aa5a]
/lib/x86_64-linux-gnu/libc.so.6(+0x84ff9)[0x7f598481cff9]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f598481bd3f]
```

```
(^q^)エンキューのキュー名=[1117]
(^q^)デキューのキュー名=[1116]
(^q^)エンキューの寿命の数=[1]
(^q^)デキューの寿命の数=[2]
```

```
			lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)0;
```

デキューの方にこれが足りないのでは？

コーディングのミスを発見したぜ。

```
	//struct ev_loop* loop;
	struct ev_loop* loop = EV_DEFAULT;
```

こうだろ。

```cpp
//--------------------------------------------------------------------------------
// OS      : Windows10 : // このプログラムは動かない
//
// OS      : Ubuntu 16.04
// Library : libev
//         : Install   : Command  : sudo apt-get update
//                                : sudo apt-get install libev-dev
// Service : RabbitMQ
//         : Reference : Web site : Top page http://www.rabbitmq.com/
//         : Install   : Web site : Installing on Debian / Ubuntu http://www.rabbitmq.com/install-debian.html
//         : Manual    : Command  : man rabbitmqctl
//         : Start     : Command  : rabbitmq-server
//         : Stop      : Command  : rabbitmqctl stop
//         : Check     : Command  : rabbitmqctl status
//         :           : Command  : rabbitmqctl list_queues
// Library : AMQP-CPP
//         : Reference : Web site : AMQP-CPP README.md https://github.com/CopernicaMarketingSoftware/AMQP-CPP
//         : Reference : Web site : QueueDeclare http://docs.spring.io/spring-amqp-net/docs/1.0.x/api/html/Spring.Messaging.Amqp.Rabbit~Spring.Messaging.Amqp.Rabbit.Connection.CachedModel~QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary).html
//         : Reference : Web site : EventingBasicConsumer https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.Events.EventingBasicConsumer.html
//         : Reference : Web site : BasicConsume https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IModel.html#method-M:RabbitMQ.Client.IModel.BasicConsume(System.UInt16,System.String,System.Boolean,System.Collections.IDictionary,RabbitMQ.Client.IBasicConsumer)
//         : Reference : Web site : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
//         : Reference : Web site : AMQP-CPP (docsforge.com) http://docsforge.com/11/AMQP-CPP/docs/latest/namespace-AMQP/class-TcpConnection/
//
// Program : this
//         : Compile   : Command  : g++ -std=c++11 tamesi35a2_cpp.cpp -o tamesi35a2_cpp.exe -lev -lamqpcpp -pthread
//         : Execute   : Command  : // バックグラウンドで実行
//                                : ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null &
//         : Stop      : Typing   : [Ctrl]+[C]
//--------------------------------------------------------------------------------
//
// メッセージの末尾に daze を付けます。
// デキューは「1112」、エンキューは「1113」キューに向けて行います。
// 標準入出力は、キーボード、画面には接続しないようにします。

#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
#include <chrono>
#include <thread> // sleep_for
#include <future> // thread

// プロセス間通信用
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>

// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
enum LifeSpanType
{
	// RabbitMQが止まってもキューを残す
	durable = 1,
	// コンシューマーが１人も接続していなかったら消す
	autodelete = 0x1 << 1,
	// キューが存在するかどうかチェックするだけ。中身見ない時これ
	passive = 0x1 << 2,
	// この接続でだけ使える。この接続が切れたら消す
	exclusive = 0x1 << 3
};

static AMQP::Address ADDRESS{ "amqp://localhost:5672" };
// 0 : enqueue用設定
// 1 : dequeue用設定
static const int ENQUEUE_INDEX = 0;
static const int DEQUEUE_INDEX = 1;
static const int NUM_INDEX = 2;
static std::string name_queues[] = { "", "" };
static LifeSpanType lifeSpan_queues[] = { (LifeSpanType)0, (LifeSpanType)0 };
static LifeSpanType LifeSpanString_To_Enum(std::string lifeSpan)
{
	if ("durable"==lifeSpan) {
		return durable;
	} else if ("autodelete" == lifeSpan) {
		return autodelete;
	} else if ("passive" == lifeSpan) {
		return passive;
	} else if ("exclusive" == lifeSpan) {
		return exclusive;
	} else {
		std::cerr << "未対応のlifeSpan [" << lifeSpan << "]";
		exit(1);
	}
}
static int LifeSpanString_To_AmqpInt(LifeSpanType lifeSpan)
{
	if (durable == lifeSpan) {
		return AMQP::durable;
	}
	else if (autodelete == lifeSpan) {
		return AMQP::autodelete;
	}
	else if (passive == lifeSpan) {
		return AMQP::passive;
	}
	else if (exclusive == lifeSpan) {
		return AMQP::exclusive;
	}
	else {
		std::cerr << "未対応のlifeSpan [" << lifeSpan << "]";
		exit(1);
	}
}

static std::string Dump()
{
	static std::ostringstream sb;
	sb << "tamesi35a2_cs.cs Dump" << std::endl
		<< "    name_queues         [ENQUEUE_INDEX]    =[" << name_queues[ENQUEUE_INDEX] << "]" << std::endl
		<< "    lifeSpan_queues     [ENQUEUE_INDEX]    =[" << lifeSpan_queues[ENQUEUE_INDEX] << "]" << std::endl
		<< "    ----" << std::endl
		<< "    name_queues         [DEQUEUE_INDEX]    =[" << name_queues[DEQUEUE_INDEX] << "]" << std::endl
		<< "    lifeSpan_queues     [DEQUEUE_INDEX]    =[" << lifeSpan_queues[DEQUEUE_INDEX] << "]" << std::endl
		<< "    ----" << std::endl;
	return sb.str();
}

// 接続はシングルトンにします
//auto* loop = EV_DEFAULT;
//struct ev_loop** loop_queues = { EV_DEFAULT, EV_DEFAULT };


/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
namespace rotationBuffer
{
	const int bufferSize = 100;
	static std::string buffer[bufferSize] = {};
	static int bufferCursors[2] = { 0, 0 };
	const int PUT_INDEX = 0;
	const int GET_INDEX = 1;

	std::mutex _mutex;
	static void putMessage(std::string message)
	{
		std::unique_lock<std::mutex> lock(_mutex);
		buffer[bufferCursors[PUT_INDEX]] = message;
		bufferCursors[PUT_INDEX]++;
		if (!(bufferCursors[PUT_INDEX] < bufferSize))
		{
			bufferCursors[PUT_INDEX] = 0;
		}
	}
	static std::string getMessage()
	{
		std::unique_lock<std::mutex> lock(_mutex);
		if ("" != buffer[bufferCursors[GET_INDEX]])
		{
			std::string message = buffer[bufferCursors[GET_INDEX]];
			buffer[bufferCursors[GET_INDEX]] = "";
			bufferCursors[GET_INDEX]++;
			if (!(bufferCursors[GET_INDEX] < bufferSize))
			{
				bufferCursors[GET_INDEX] = 0;
			}
			return message;
		}
		return "";
	}
}

// メッセージキューにエンキュー
static void enqueue(std::string message)
{
	std::cout << "（＾▽＾）エンキュー開始だぜ☆" << std::endl;

	// エンキュー用の接続
	//struct ev_loop* loop;
	struct ev_loop* loop = EV_DEFAULT;

	AMQP::LibEvHandler handler{ loop };
	//AMQP::LibEvHandler handler{ loop_queues[ENQUEUE_INDEX] };
	AMQP::TcpConnection connection{ &handler, ADDRESS };
	std::cout << "（＾▽＾）接続したぜ☆" << std::endl;
	AMQP::TcpChannel channel{ &connection };
	std::cout << "（＾▽＾）チャンネル開いたぜ☆" << std::endl;

	std::string exchange_name = "myexchange";
	std::string routing_key = "";

	int lifeSpan = LifeSpanString_To_AmqpInt(lifeSpan_queues[ENQUEUE_INDEX]);

	channel.declareQueue(name_queues[ENQUEUE_INDEX], lifeSpan)
		.onError([&lifeSpan](const char* errMsg) {
		std::cerr << "error declaring queue: " << errMsg << " lifeSpan=[" << lifeSpan << "]" << "\n";
	});
	std::cout << "（＾▽＾）デクレア・キューしたぜ☆" << std::endl;

	channel.bindQueue(exchange_name, name_queues[ENQUEUE_INDEX], routing_key)
		.onSuccess([&connection, &channel, &exchange_name, &routing_key, &message]() {

		if (!channel.publish(exchange_name, routing_key, message.c_str(), message.size())) {
			std::cerr << "failed to publish?\n";
		}

		// break in ev loop.
		connection.close();
	});
	std::cout << "（＾▽＾）バインド・キューしたぜ☆" << std::endl;

	// このループは、パブリッシュ後に抜ける
	ev_run(loop);
	//ev_run(loop_queues[ENQUEUE_INDEX]);
}

// 受信できたときに割り込んでくる処理
// startConsume() しておくこと。
static std::string dequeue() {
	std::string message;

	while ("" == message)
	{
		message = rotationBuffer::getMessage();
	}

	return message;
}

//// メッセージ・キューの送信を担当
//static void workProduce()
//{
//
//}

// メッセージ・キューの監視を開始
static void workConsume()
{
	std::cout << "(^q^)コンシューム開始だぜ☆" << std::endl;

	// Connect to the AMQP service.
	//struct ev_loop* loop;
	struct ev_loop* loop = EV_DEFAULT;

	AMQP::LibEvHandler handler{ loop };
	//AMQP::LibEvHandler handler(loop_queues[DEQUEUE_INDEX]);
	AMQP::TcpConnection connection(&handler, ADDRESS);
	std::cout << "(^q^)接続したぜ☆" << std::endl;
	AMQP::TcpChannel channel(&connection);
	std::cout << "(^q^)チャンネル開いたぜ☆" << std::endl;

	// I will go to the front of the box named "1111".
	int lifeSpan = LifeSpanString_To_AmqpInt(lifeSpan_queues[DEQUEUE_INDEX]);
	channel.declareQueue(name_queues[DEQUEUE_INDEX], lifeSpan);
	std::cout << "(^q^)デクレア・キューしたぜ☆" << std::endl;

	// I look inside the box.
	auto errorCb = [&lifeSpan](const char *errMsg) {
		std::cerr << "My ID watching failed [" << errMsg << "] lifeSpan=[" << lifeSpan << "]" << std::endl;
	};
	auto messageCb = [&channel](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {

		std::string myString(message.body(), message.bodySize());
		rotationBuffer::putMessage(myString);

		channel.ack(deliveryTag);
	};
	channel.consume(name_queues[DEQUEUE_INDEX])
		.onReceived(messageCb)
		.onError(errorCb);
	std::cout << "(^q^)コンシュームしたぜ☆" << std::endl;

	// I will keep on forever.
	ev_run(loop);
	//ev_run(loop_queues[DEQUEUE_INDEX], 0);

	// I will not come here.
	return;
}

int main(int argc, char* argv[])
{
	std::cout << "(^q^)Welcome! AMQP::durable=[" << AMQP::durable << "] AMQP::autodelete=[" << AMQP::autodelete << "] AMQP::passive=[" << AMQP::passive << "] AMQP::exclusive=[" << AMQP::exclusive << "]" << std::endl;

	// 引数の解析
	if(0<argc)
	{
		// プログラム名を省き、コマンドライン引数だけをつなげる。
		std::string cmdArg;
		for (int i = 1; i < argc; ++i)
		{
			cmdArg += std::string(argv[i]);
			if (i < argc) {
				cmdArg += " ";
			}
		}
		std::cout << "(^q^)cmdArg=[" << cmdArg << "]" << std::endl;
		std::istringstream data(cmdArg);
		//data >> std::skipws;
		std::cout << "(^q^)data.str()=[" << data.str() << "]" << std::endl;

		// 与件
		// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
		// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」

		// 受け皿
		std::string queueNames[2] = {}; // 結果はこれらの配列に入れる
		std::vector<std::string> lifespans[2] = {};

		// 記憶
		int m0 = -1; // 0:enqueue, 1:dequeue
		int m1 = -1; // lifespans index.

		// 解析器
		std::string a;
		while (data >> a) {
			std::cout << "(^_^)a0=[" << a << "]" << std::endl;

			if ("--enqueue" == a)
			{
				std::cout << "(^q^)エンキュー!" << std::endl;
				m0 = 0;
				m1 = -1;
			}
			else if ("--dequeue" == a)
			{
				std::cout << "(^q^)デキュー!" << std::endl;
				m0 = 1;
				m1 = -1;
			}
			else if (-1 == m1 && 0 == m0) {
				std::cout << "(^q^)エンキューのキュー名!" << std::endl;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
				m1++;
			}
			else if (-1 == m1 && 1 == m0) {
				std::cout << "(^q^)デキューのキュー名!" << std::endl;
				queueNames[m0] = a; // キュー名
				lifespans[m0] = std::vector<std::string>();// 配列の中にリストを準備
				m1++;
			}
			else
			{
				std::cout << "(^q^)寿命! m0=[" << m0 << "] m1=[" << m1 << "]" << std::endl;
				lifespans[m0].push_back(a);
				std::cout << "(^q^)zyumyo-!" << std::endl;
			} // 要素数-1 で最後の要素
		}
		std::cout << "(^-^)Loop end." << std::endl;

		if ("" == queueNames[0] || "" == queueNames[1]) {
			std::cerr << "コマンドライン引数の「--enqueue キュー名 寿命」「--dequeue キュー名 寿命」を漏れなく指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete" << std::endl;
			std::cerr << "queueNames[0]=[" << queueNames[0] << "]" << std::endl;
			//std::cerr << "queueNames[1]=[" << queueNames[1] << "]" << std::endl;
			//std::cerr << Dump();
			exit(1);
		}
		std::cout << "(^q^)エンキューのキュー名=[" << queueNames[0] << "]" << std::endl;
		std::cout << "(^q^)デキューのキュー名=[" << queueNames[1] << "]" << std::endl;
		std::cout << "(^q^)エンキューの寿命の数=[" << lifespans[0].size() << "]" << std::endl;
		std::cout << "(^q^)デキューの寿命の数=[" << lifespans[1].size() << "]" << std::endl;

		// エンキュー
		{
			m0 = 0;
			name_queues[ENQUEUE_INDEX] = queueNames[m0];
			lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)0;
			{
				for (std::string lifespan : lifespans[m0])
				{
					lifeSpan_queues[ENQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[ENQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
				}
			}
		}
		std::cout << "(^q^)エンキューおわり name_queues[ENQUEUE_INDEX]=[" << name_queues[ENQUEUE_INDEX] << "] lifeSpan_queues[ENQUEUE_INDEX]=[" << lifeSpan_queues[ENQUEUE_INDEX] << "]" << std::endl;

		// デキュー
		{
			m0 = 1;
			name_queues[DEQUEUE_INDEX] = queueNames[m0];
			lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)0;
			{
				for (std::string lifespan : lifespans[m0])
				{
					lifeSpan_queues[DEQUEUE_INDEX] = (LifeSpanType)((int)lifeSpan_queues[DEQUEUE_INDEX] | (int)LifeSpanString_To_Enum(lifespan));
				}
			}
		}
		std::cout << "(^q^)デキューおわり name_queues[DEQUEUE_INDEX]=[" << name_queues[DEQUEUE_INDEX] << "] lifeSpan_queues[DEQUEUE_INDEX]=[" << lifeSpan_queues[DEQUEUE_INDEX] << "]" << std::endl;

		std::cout << Dump();
		std::cout << "(^q^)ダンプおわり" << std::endl;
	}
	else
	{
		std::cerr << "コマンドライン引数を指定してください。例: --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete";
		exit(1);
	}

	// デキューの常時監視をスタート
	auto th1 = std::thread([] { workConsume(); });

	// 無限ループ
	std::cout << "(^q^)メッセージ監視ループに入るぜ☆" << std::endl;
	for (;;)
	{
		std::string message = rotationBuffer::getMessage();
		if ("" != message)
		{
			std::cout << "(^q^)メッセージを受け取ったか？" << std::endl;

			// 末尾に daze を付ける。
			message += "daze";

			// エンキューする
			enqueue( message);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}

	// このプログラムは、自分では接続を切らない。

	// th1 スレッドの終了を待つ
	th1.join();

	std::cout << "(^q^)Finished!" << std::endl;
	return 0;
}
```

これでメモリ・リークはしてないぜ。

```
# ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null &
[1] 18787
```

標準入力も捨てておくぜ。

```
# cd ..
[1]+  Exit 1                  ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null  (wd: /home/★user/shogi/cpp_service)
(wd now: /home/★user/shogi)
```

おや、終了している？

tamesi35a2_cpp.out.log

```
(^q^)Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
(^q^)cmdArg=[--enqueue 1113 durable --dequeue 1112 durable autodelete ]
(^q^)data.str()=[--enqueue 1113 durable --dequeue 1112 durable autodelete ]
(^_^)a0=[--enqueue]
(^q^)エンキュー!
(^_^)a0=[1113]
(^q^)エンキューのキュー名!
(^_^)a0=[durable]
(^q^)寿命! m0=[0] m1=[0]
(^q^)zyumyo-!
(^_^)a0=[--dequeue]
(^q^)デキュー!
(^_^)a0=[1112]
(^q^)デキューのキュー名!
(^_^)a0=[durable]
(^q^)寿命! m0=[1] m1=[0]
(^q^)zyumyo-!
(^_^)a0=[autodelete]
(^q^)寿命! m0=[1] m1=[0]
(^q^)zyumyo-!
(^-^)Loop end.
(^q^)エンキューのキュー名=[1113]
(^q^)デキューのキュー名=[1112]
(^q^)エンキューの寿命の数=[1]
(^q^)デキューの寿命の数=[2]
(^q^)エンキューおわり name_queues[ENQUEUE_INDEX]=[1113] lifeSpan_queues[ENQUEUE_INDEX]=[1]
(^q^)デキューおわり name_queues[DEQUEUE_INDEX]=[1112] lifeSpan_queues[DEQUEUE_INDEX]=[3]
tamesi35a2_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[1]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[3]
    ----
(^q^)ダンプおわり
(^q^)メッセージ監視ループに入るぜ☆
(^q^)コンシューム開始だぜ☆
(^q^)接続したぜ☆
(^q^)チャンネル開いたぜ☆
```

```
# nano tamesi35a2_cpp.err.log
```

```
未対応のlifeSpan [3]
```

1 と 2 を足して 3 なんだが　コード書いてなかったか。

```cpp
static int LifeSpanString_To_AmqpInt(LifeSpanType lifeSpan)
{
	int amqpInt = 0;
	if ( ((int)durable & (int)lifeSpan) == (int)durable) {
		amqpInt |= AMQP::durable;
	}
	
	if (((int)autodelete & (int)lifeSpan) == (int)autodelete) {
		amqpInt |= AMQP::autodelete;
	}
	
	if (((int)passive & (int)lifeSpan) == (int)passive) {
		amqpInt |= AMQP::passive;
	}
	
	if (((int)exclusive & (int)lifeSpan) == (int)exclusive) {
		amqpInt |= AMQP::exclusive;
	}

	return amqpInt;
}
```

これでどうか？

```
# jobs
[1]+  Running                 ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null &
```

```
# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1112
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1113
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1113]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > usi
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1112]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [False]
    nowait は仮に false 固定
    arguments は仮に null 固定

Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue '1112' in vhost '/': received 'false' but current is 'true'", classId=50, methodId=10, cause=
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40459fe0 + 0x00103> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40457da0 + 0x000f9> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x4045cf00 + 0x00113> in <filename unknown>:0
  at UsagiMQ.Program.GetChannel (Int32 index) <0x4041d8c0 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x4045dfe0 + 0x00013> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x40418d50 + 0x009a7> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue '1112' in vhost '/': received 'false' but current is 'true'", classId=50, methodId=10, cause=
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40459fe0 + 0x00103> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40457da0 + 0x000f9> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x4045cf00 + 0x00113> in <filename unknown>:0
  at UsagiMQ.Program.GetChannel (Int32 index) <0x4041d8c0 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x4045dfe0 + 0x00013> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x40418d50 + 0x009a7> in <filename unknown>:0
```

さて、何だったか。

tamesi34_cs.cs

```csharp
// OS  : Windows 10
// IDE : Visual Studio 2015
//       Install : NuGet   : Install-Package RabbitMQ.Client -Version 4.1.1
//
// OS  : Ubuntu 16.04
//       Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi34_cs.cs
//       Execute : Command : // フォアグラウンドで実行する
//                         : ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
//       Check   : Command : // キューの中身の数を調べる
//                         : rabbitmqctl list_queues
//
// Library : RabbitMQ
//           Refference : Website : RabbitMQ http://www.rabbitmq.com/
//                      : Website : RabbitMQ管理コマンド（rabbitmqctl）使い方 (Qiita) http://qiita.com/tamikura@github/items/5293cda4c0026b2d7022
//                      : Website : amqpを使ってRabbitMQのキューを操作する (Qiita) http://qiita.com/tamikura@github/items/a268afa51c5537ca4fe6
//--------------------------------------------------------------------------------
// tamesi34_cs.cs

// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace UsagiMQ
{
    /// <summary>
    /// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
    /// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
    /// </summary>
    [Flags]
    enum LifeSpanType
    {
        /// <summary>
        /// RabbitMQが止まってもキューを残す
        /// </summary>
        Durable = 1,
        /// <summary>
        /// コンシューマーが１人も接続していなかったら消す
        /// </summary>
        Autodelete = 0x1<<1,
        /// <summary>
        /// キューが存在するかどうかチェックするだけ。中身見ない時これ
        /// </summary>
        Passive = 0x1 << 2,
        /// <summary>
        /// この接続でだけ使える。この接続が切れたら消す
        /// </summary>
        Exclusive = 0x1 << 3
    }

    /// <summary>
    /// メッセージを　エンキューします。
    /// キューの名前は指定してください。
    /// デキューは割込みを受け付けます。
    /// 
    /// 参照 : QueueDeclare (v1.0) http://docs.spring.io/spring-amqp-net/docs/1.0.x/api/html/Spring.Messaging.Amqp.Rabbit~Spring.Messaging.Amqp.Rabbit.Connection.CachedModel~QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary).html
    /// 参照 : EventingBasicConsumer https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.Events.EventingBasicConsumer.html
    /// 参照 : QueueDelete (v1.4) https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IModel.html#method-M:RabbitMQ.Client.IModel.QueueDelete(System.UInt16,System.String,System.Boolean,System.Boolean,System.Boolean)
    /// 参照 : BasicConsume https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IModel.html#method-M:RabbitMQ.Client.IModel.BasicConsume(System.UInt16,System.String,System.Boolean,System.Collections.IDictionary,RabbitMQ.Client.IBasicConsumer)
    /// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
    /// </summary>
    class Program
    {
        static string Dump()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("tamesi34_cs.cs Dump");
            sb.AppendLine("    name_queues         [ENQUEUE_INDEX]    =[" + name_queues[ENQUEUE_INDEX]+"]");
            sb.AppendLine("    lifeSpan_queues     [ENQUEUE_INDEX]    =[" + lifeSpan_queues[ENQUEUE_INDEX] + "]");
            sb.AppendLine("    durable_lifeSpans   [ENQUEUE_INDEX]    =[" + durable_lifeSpans[ENQUEUE_INDEX] + "]");
            sb.AppendLine("    autodelete_lifeSpans[ENQUEUE_INDEX]    =[" + autodelete_lifeSpans[ENQUEUE_INDEX] + "]");
            sb.AppendLine("    passive_lifeSpans   [ENQUEUE_INDEX]    =[" + passive_lifeSpans[ENQUEUE_INDEX] + "]");
            sb.AppendLine("    exclusive_lifeSpans [ENQUEUE_INDEX]    =[" + exclusive_lifeSpans[ENQUEUE_INDEX] + "]");
            sb.AppendLine("    ----");
            sb.AppendLine("    name_queues         [DEQUEUE_INDEX]    =[" + name_queues[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    lifeSpan_queues     [DEQUEUE_INDEX]    =[" + lifeSpan_queues[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    durable_lifeSpans   [DEQUEUE_INDEX]    =[" + durable_lifeSpans[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    autodelete_lifeSpans[DEQUEUE_INDEX]    =[" + autodelete_lifeSpans[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    passive_lifeSpans   [DEQUEUE_INDEX]    =[" + passive_lifeSpans[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    exclusive_lifeSpans [DEQUEUE_INDEX]    =[" + exclusive_lifeSpans[DEQUEUE_INDEX] + "]");
            sb.AppendLine("    ----");
            sb.AppendLine("    name_queues         [DELETEQUEUE_INDEX]=[" + name_queues[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    lifeSpan_queues     [DELETEQUEUE_INDEX]=[" + lifeSpan_queues[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    durable_lifeSpans   [DELETEQUEUE_INDEX]=[" + durable_lifeSpans[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[" + autodelete_lifeSpans[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    passive_lifeSpans   [DELETEQUEUE_INDEX]=[" + passive_lifeSpans[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[" + exclusive_lifeSpans[DELETEQUEUE_INDEX] + "]");
            sb.AppendLine("    ----");
            return sb.ToString();
        }

        const int ENQUEUE_INDEX = 0;
        const int DEQUEUE_INDEX = 1;
        const int DELETEQUEUE_INDEX = 2;
        const int NUM_INDEX = 3;
        const string HOST_NAME = "localhost";
        static string[] name_queues = new string[NUM_INDEX];
        /// <summary>
        /// キューの寿命（複合可能）
        /// durable    : RabbitMQが止まってもキューを残す
        /// autodelete : コンシューマーが１人も接続していなかったら消す
        /// passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
        /// exclusive  : この接続でだけ使える。この接続が切れたら消す
        /// </summary>
        static LifeSpanType[] lifeSpan_queues = new LifeSpanType[NUM_INDEX];
        static bool[]
            durable_lifeSpans = new bool[NUM_INDEX],
            autodelete_lifeSpans = new bool[NUM_INDEX],
            passive_lifeSpans = new bool[NUM_INDEX],
            exclusive_lifeSpans = new bool[NUM_INDEX];
        static void SetLifeSpan(int index_queue, string name_queue, LifeSpanType lifeSpan)
        {
            name_queues[index_queue] = name_queue;
            lifeSpan_queues[index_queue] = lifeSpan;

            // 一旦クリアー
            durable_lifeSpans[index_queue] = false;
            autodelete_lifeSpans[index_queue] = false;
            passive_lifeSpans[index_queue] = false;
            exclusive_lifeSpans[index_queue] = false;

            // durable
            if (((int)lifeSpan & (int)LifeSpanType.Durable) == (int)LifeSpanType.Durable) { durable_lifeSpans[index_queue] = true; }
            // autodelete
            if (((int)lifeSpan & (int)LifeSpanType.Autodelete) == (int)LifeSpanType.Autodelete) { autodelete_lifeSpans[index_queue] = true; }
            // passive
            if (((int)lifeSpan & (int)LifeSpanType.Passive) == (int)LifeSpanType.Passive) { passive_lifeSpans[index_queue] = true; }
            // exclusive
            if (((int)lifeSpan & (int)LifeSpanType.Exclusive) == (int)LifeSpanType.Exclusive) { exclusive_lifeSpans[index_queue] = true; }
        }


        public static ConnectionFactory GetFactory()
        {
            if (null == m_factory_)
            {
                m_factory_ = new ConnectionFactory() { HostName = HOST_NAME };
                Console.WriteLine("(^q^)ファクトリーを用意したぜ☆ HostName=[" + HOST_NAME + "]");
            }
            return m_factory_;
        }
        static ConnectionFactory m_factory_;

        public static IConnection GetConnection()
        {
            if (null == m_connection_)
            {
                m_connection_ = GetFactory().CreateConnection();
                Console.WriteLine("(^q^)接続したぜ☆");
            }
            return m_connection_;
        }
        static IConnection m_connection_;

        public static IModel GetChannel(int index)
        {
            if (null == m_channels_[index])
            {
                m_channels_[index] = GetConnection().CreateModel();

                // 引数が7つの QueueDeclare でエラーを吐くことがあるので、情報を出力しておく。
                Console.Error.WriteLine(Dump());
                Console.Error.WriteLine("(tamesi34_cs.cs?) GetChannel index = [" + index + "]");
                Console.Error.WriteLine("    name_queues[index] = [" + name_queues[index] + "]");
                Console.Error.WriteLine("    passive_lifeSpans[index] = [" + passive_lifeSpans[index] + "]");
                Console.Error.WriteLine("    durable_lifeSpans[index] = [" + durable_lifeSpans[index] + "]");
                Console.Error.WriteLine("    exclusive_lifeSpans[index] = [" + exclusive_lifeSpans[index] + "]");
                Console.Error.WriteLine("    autodelete_lifeSpans[index] = [" + autodelete_lifeSpans[index] + "]");
                Console.Error.WriteLine("    nowait は仮に false 固定");
                Console.Error.WriteLine("    arguments は仮に null 固定");

#if UBUNTU
                // Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
                // RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments)
                // そして false になっているようだ。
                m_channels_[index].QueueDeclare(name_queues[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
                //m_channels_[index].QueueDeclare(name_queues[index], false, false, false, false, false, null);
#else
                m_channels_[index].QueueDeclare(name_queues[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
            }

            Console.WriteLine("(^q^)チャンネルを開いたぜ☆ message=[" + index + "]");
            return m_channels_[index];
        }
        static IModel[] m_channels_ = new IModel[NUM_INDEX];

        public static EventingBasicConsumer GetConsumer(int index)
        {
            if (null == m_consumers_[index])
            {
#if UBUNTU
                // Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個～6個のものは無かった。
                m_consumers_[index] = new EventingBasicConsumer();
#else
                m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
            }
            Console.WriteLine("(^q^)コンシューマーを取得したぜ☆ index=["+ index + "]");
            return m_consumers_[index];
        }
        static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[NUM_INDEX];

        /// <summary>
        /// 受信できたときに割り込んでくる処理
        /// </summary>
#if UBUNTU
        public static BasicDeliverEventHandler GetDequeueHandler()
#else
        public static EventHandler<BasicDeliverEventArgs> GetDequeueHandler()
#endif
        {
            if (null == m_dequeueHandler_)
            {
#if UBUNTU
                m_dequeueHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
                m_dequeueHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
                {
                    byte[] body = ea.Body;
                    string message = Encoding.UTF8.GetString(body);
                    Console.WriteLine("<---- [interrupt!] Dequeue(^q^) {0}", message);
                });
            }

            return m_dequeueHandler_;
        }

#if UBUNTU
        static BasicDeliverEventHandler m_dequeueHandler_;
#else
        static EventHandler<BasicDeliverEventArgs> m_dequeueHandler_;
#endif

        /// <summary>
        /// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
        /// </summary>
        static void CloseConnection()
        {
            if (null != m_connection_)
            {
                m_connection_.Close();
                m_connection_ = null;
                Console.WriteLine("(^q^)接続を閉じたぜ☆");
            }
        }
        /// <summary>
        /// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
        /// </summary>
        static void CloseChannel(int index)
        {
            if (null != m_channels_[index])
            {
                m_channels_[index].Close();
                m_channels_[index] = null;
                Console.WriteLine("(^q^)チャンネルを閉じたぜ☆");
            }
        }

        static void Main(string[] args)
        {
            //----------------------------------------
            // Delete
            //----------------------------------------
            for (;;)
            {
                Console.Write(@"削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > ");
                string queueName_delete = Console.ReadLine();
                if (""== queueName_delete.Trim())
                {
                    break;
                }

                
                Console.Write(@"削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
("+ ((int)LifeSpanType.Durable) + @") durable    : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが１人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
                LifeSpanType lifeSpan_delete = (LifeSpanType)int.Parse(Console.ReadLine());
                SetLifeSpan(DELETEQUEUE_INDEX, queueName_delete, lifeSpan_delete);
                uint result = DeleteQueue();
                Console.WriteLine(@"["+ queueName_delete + "]キューを削除したはずだぜ☆（＾～＾） result=["+ result + "]");
            }

            //----------------------------------------
            // Enqueue settings
            //----------------------------------------
            for (;;)
            {
                Console.Write(@"エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > ");
                string queueName_enqueue = Console.ReadLine();

                Console.Write(@"エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(" + ((int)LifeSpanType.Durable) + @") durable    : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが１人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
                int lifeSpan_enqueue;
                if(int.TryParse(Console.ReadLine(),out lifeSpan_enqueue))
                {
                    SetLifeSpan(ENQUEUE_INDEX, queueName_enqueue, (LifeSpanType)lifeSpan_enqueue);
                    break;
                }
            }

            //----------------------------------------
            // Enqueue settings
            //----------------------------------------
            for (;;)
            {
                Console.Write(@"デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > ");
                string queueName_dequeue = Console.ReadLine();

                Console.Write(@"デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(" + ((int)LifeSpanType.Durable) + @") durable    : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが１人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
                int lifeSpan_dequeue;
                if(int.TryParse(Console.ReadLine(),out lifeSpan_dequeue))
                {
                    SetLifeSpan(DEQUEUE_INDEX, queueName_dequeue, (LifeSpanType)lifeSpan_dequeue);

                    StartConsume();
                    break;
                }
            }

            Console.Write(@"終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > ");
            for (;;)
            {
                // "Hello World!" などを入力
                string line = Console.ReadLine();
                Enqueue(line);
                Console.Write(@"Enqueue? > ");
            }

            // ここには来ない
            // CloseConnection();
        }

        static uint DeleteQueue()
        {
            IModel channel = GetChannel(DELETEQUEUE_INDEX);

#if UBUNTU
            // Ubuntuでは何故か 昔の .Net 用の引数 5 つのやつの変則版になっている。
            // uint QueueDelete(ushort ticket, string queue, bool ifUnused, bool ifEmpty, bool nowait)
            uint result = channel.QueueDelete( name_queues[DELETEQUEUE_INDEX],true,true,true);
#else
            uint result = channel.QueueDelete(name_queues[DELETEQUEUE_INDEX],true,true);
#endif

            // 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
            CloseChannel(DELETEQUEUE_INDEX);
            return result;
        }

        static void Enqueue(string message)
        {
            Console.WriteLine("(^q^)Enqueue: エンキュー開始☆ message=[" + message + "]");

            IModel channel = GetChannel(ENQUEUE_INDEX);

            byte[] body = Encoding.UTF8.GetBytes(message);
            Console.WriteLine("(^q^)Enqueue: body.Length=[" + body.Length+"]");

            channel.BasicPublish("", name_queues[ENQUEUE_INDEX], null, body);
            Console.WriteLine("(^q^)Enqueue: パブリッシュしたぜ。キュー名=[" + name_queues[ENQUEUE_INDEX] + "]");

            // 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
            CloseChannel(ENQUEUE_INDEX);
        }

        static void StartConsume()
        {
            IModel channel = GetChannel(DEQUEUE_INDEX);
            EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);

            // 受信できたときに割り込んでくる処理
            consumer.Received += GetDequeueHandler();

#if UBUNTU
            // Ubuntuでは何故か引数が 5 個のやつになっている。
            channel.BasicConsume( name_queues[DEQUEUE_INDEX], true, "", null, consumer);
#else
            channel.BasicConsume( name_queues[DEQUEUE_INDEX], true, consumer);
#endif
            // 終了はさせない
            // consumer.Received -= GetReceiveHandler();
            // CloseChannel(DEQUEUE_INDEX);
        }
    }
}
```

```
root@tk2-217-18401:/home/★user/shogi/csharp_service# mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi34_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1112
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1113
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 2
(^q^)ファクトリーを用意したぜ☆ HostName=[localhost]
(^q^)接続したぜ☆
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[False]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1113]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [False]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
(^q^)チャンネルを開いたぜ☆ message=[1]
(^q^)コンシューマーを取得したぜ☆ index=[1]
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > usi
(^q^)Enqueue: エンキュー開始☆ message=[usi]
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[False]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Autodelete]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[False]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[True]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1112]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [False]
    nowait は仮に false 固定
    arguments は仮に null 固定
```

反応がない。

tamesi34_cs.err.log

```
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue '1112' in vhost '/':$
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41a40570 + 0x00107> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41a3e3f0 + 0x000fd> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41a43420 + 0x00113> in <filename unk$
  at UsagiMQ.Program.GetChannel (Int32 index) <0x41a03d10 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x41a44550 + 0x00047> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x419fed50 + 0x009a7> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'auto_del$
  at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41a40570 + 0x00107> in <filename unknown>:0
  at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41a3e3f0 + 0x000fd> in <filename unknown>:0
  at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41a43420 + 0x00113> in <filename unk$
  at UsagiMQ.Program.GetChannel (Int32 index) <0x41a03d10 + 0x0045c> in <filename unknown>:0
  at UsagiMQ.Program.Enqueue (System.String message) <0x41a44550 + 0x00047> in <filename unknown>:0
  at UsagiMQ.Program.Main (System.String[] args) <0x419fed50 + 0x009a7> in <filename unknown>:0
```

```
# jobs
[1]+  Running                 ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null &  (wd: /home/★user/shogi/cpp_service)
```

寿命が違うのか？

```
root@tk2-217-18401:/home/★user/shogi/csharp_service# jobs
[1]+  Running                 ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null &  (wd: /home/★user/shogi/cpp_service)
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆（＾～＾）
キュー名を入力    : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1112
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
デキュー先のメッセージ・キューの名前を入れろだぜ☆（＾～＾）
Queue name? > 1113
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆（＾～＾）
(1) durable    : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが１人も接続していなかったら消す
(4) passive    : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive  : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
(^q^)ファクトリーを用意したぜ☆ HostName=[localhost]
(^q^)接続したぜ☆
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[True]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[False]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [1]
    name_queues[index] = [1113]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [False]
    nowait は仮に false 固定
    arguments は仮に null 固定
(^q^)チャンネルを開いたぜ☆ message=[1]
(^q^)コンシューマーを取得したぜ☆ index=[1]
終了するときは[Ctrl]+[C]キーを押せだぜ☆（＾～＾）
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(＾◇＾)
Enqueue? > usi
(^q^)Enqueue: エンキュー開始☆ message=[usi]
tamesi34_cs.cs Dump
    name_queues         [ENQUEUE_INDEX]    =[1112]
    lifeSpan_queues     [ENQUEUE_INDEX]    =[Durable, Autodelete]
    durable_lifeSpans   [ENQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[ENQUEUE_INDEX]    =[True]
    passive_lifeSpans   [ENQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [ENQUEUE_INDEX]    =[False]
    ----
    name_queues         [DEQUEUE_INDEX]    =[1113]
    lifeSpan_queues     [DEQUEUE_INDEX]    =[Durable]
    durable_lifeSpans   [DEQUEUE_INDEX]    =[True]
    autodelete_lifeSpans[DEQUEUE_INDEX]    =[False]
    passive_lifeSpans   [DEQUEUE_INDEX]    =[False]
    exclusive_lifeSpans [DEQUEUE_INDEX]    =[False]
    ----
    name_queues         [DELETEQUEUE_INDEX]=[]
    lifeSpan_queues     [DELETEQUEUE_INDEX]=[0]
    durable_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
    passive_lifeSpans   [DELETEQUEUE_INDEX]=[False]
    exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
    ----

(tamesi34_cs.cs?) GetChannel index = [0]
    name_queues[index] = [1112]
    passive_lifeSpans[index] = [False]
    durable_lifeSpans[index] = [True]
    exclusive_lifeSpans[index] = [False]
    autodelete_lifeSpans[index] = [True]
    nowait は仮に false 固定
    arguments は仮に null 固定
(^q^)チャンネルを開いたぜ☆ message=[0]
(^q^)Enqueue: body.Length=[3]
(^q^)Enqueue: パブリッシュしたぜ。キュー名=[1112]
(^q^)チャンネルを閉じたぜ☆
Enqueue? >
```

パブリッシュはできたが。

```
[1]+  Aborted                 ./tamesi35a2_cpp.exe --enqueue 1113 durable --dequeue 1112 durable autodelete > ./tamesi35a2_cpp.out.log 2> ./tamesi35a2_cpp.err.log < /dev/null  (wd: /home/★user/shogi/cpp_service)
(wd now: /home/★user/shogi/csharp_service)
```

tamesi35a2_cpp.err.log

```
tamesi35a2_cpp.exe: ev.c:3541: ev_run: Assertion `("libev: ev_loop recursion during release detected", ((loop)->loop_done) != 0x80)' failed.
```

# 記事が長くなったので次へ