ホームページ  >  記事  >  バックエンド開発  >  C++ マルチスレッド プログラミングの概要

C++ マルチスレッド プログラミングの概要

黄舟
黄舟オリジナル
2017-02-06 14:02:111445ブラウズ

C++ プログラムを開発する場合、一般にスループット、同時実行性、リアルタイム パフォーマンスの点でより高い要件が求められます。 C++ プログラムを設計する場合、要約すると、次の点から効率を向上させることができます:

  • 同時実行性

  • 非同期

  • キャッシュ

ここでは、私が日常的に遭遇するいくつかの問題の例をいくつか示します。作品の設計思想は上記の3点にほかなりません。

1 タスクキュー

1.1 プロデューサー-コンシューマーモデルに基づいてタスクキューを設計する

プロデューサー-コンシューマーモデルは、たとえばサーバープログラムでユーザーデータが変更されるときによく知られているモデルです。ロジックモジュールにより、データベースを更新するタスクが生成(プロデュース)され、IOモジュールのタスクキューに渡されます。IOモジュールはタスクキューからタスクを取り出し、SQL操作を実行します(コンシューム)。

一般的なタスク キューを設計します。サンプル コードは次のとおりです:

詳細な実装は次の場所にあります:

http://ffown.googlecode.com/svn/trunk/fflib/include/detail/task_queue_impl.h

void task_queue_t::produce(const task_t& task_) {
lock_guard_t lock(m_mutex);
if (m_tasklist->empty()){
//! 条件满足唤醒等待线程
m_cond.signal();
}
m_tasklist->push_back(task_);
}
int task_queue_t::comsume(task_t& task_){
lock_guard_t lock(m_mutex);
while (m_tasklist->empty())
//! 当没有作业时,就等待直到条件满足被唤醒{
if (false == m_flag){
return -1;
}
m_cond.wait();
}
task_ = m_tasklist->front();
m_tasklist->pop_front();
return 0;
}


1.2 タスクキューを使用するためのヒント

1.2.1 IOとロジックの分離

たとえば、オンラインゲームサーバープログラムでは、ネットワークモジュールはメッセージパケットを受信し、それをロジック層に配信した後すぐに戻ります、次のメッセージ パケットの受け入れを続けます。論理スレッドは、リアルタイムのパフォーマンスを確保するために、IO 操作のない環境で実行されます。例:

void handle_xx_msg(long uid, const xx_msg_t& msg){
logic_task_queue->post(boost::bind(&servie_t::proces, uid, msg));
}


このモードはシングル タスク キューであり、各タスク キューはシングル スレッドであることに注意してください。

1.2.2 並列パイプライン

上記は、IO および CPU 操作の並列化のみを完了しますが、CPU での論理操作はシリアルです。場合によっては、CPU ロジック演算部分も並列化できます。たとえば、ゲームでは、ユーザー A とユーザー B の 2 つの操作はデータを共有しないため、完全に並列化できます。最も簡単な方法は、A と B に関連する操作を別のタスク キューに割り当てることです。例は次のとおりです。

void handle_xx_msg(long uid, const xx_msg_t& msg) {
logic_task_queue_array[uid % sizeof(logic_task_queue_array)]->post(
boost::bind(&servie_t::proces, uid, msg));
}


このモードはマルチタスク キューであり、各タスク キューはシングルスレッドであることに注意してください。


1.2.3 接続プールと非同期コールバック

たとえば、論理サービス モジュールでは、データベース モジュールがユーザー データを非同期でロードし、後続の処理と計算を実行する必要があります。データベース モジュールには、固定数の接続を持つ接続プールがあり、SQL を実行するタスクが到着すると、アイドル状態の接続を選択し、SQL を実行し、コールバック関数を通じて SQL をロジック層に渡します。手順は次のとおりです。

スレッド プールを事前に割り当て、各スレッドがデータベースへの接続を作成します

データベース モジュールのタスク キューを作成し、すべてのスレッドがこのタスク キューのコンシューマになります

ロジック層データベースモジュールを考慮します SQL 実行タスクを配信し、SQL 実行結果を受け取るコールバック関数を渡します

例は次のとおりです:

void db_t:load(long uid_, boost::functionpost(boost::bind(&db_t:load, uid, func));

このモードは単一のタスクキューであり、各タスクキューはマルチスレッドであることに注意してください。


2. ログ

この記事では主に C++ マルチスレッド プログラミングについて説明します。ログ システムはプログラムの効率を向上させるためのものではありませんが、プログラムのデバッグや実行時のトラブルシューティングにとって、ログは開発においてかけがえのないツールであると私は信じています。友人がログを使用するバックグラウンド プログラム。一般的なログの使用方法には次のようなものがあります:


ストリーミング (logstream << "start service time[%d]" <
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。