コラボレーションライブラリlibco学習の使用例
概要
libcoは微信バックグラウンドで大規模に使用されているc/c++コラボレーションライブラリであり、2013年から現在まで微信バックグラウンドの数万台の機器で安定して稼働している.
libcoは、いくつかの関数インタフェースco_のみを介してcreate/co_resume/co_yield再配合co_pollは、スレッドライブラリのように簡単に同期または非同期の書き方をサポートします.同時にライブラリにはsocketファミリー関数のhookが提供されており,バックグラウンド論理サービスは論理コードをほとんど修正することなく非同期化改造を完了できる.
libcoはソースコードが簡潔で効率的なコラボレーションライブラリであり、ソースコードを読むことでコラボレーションの概念と技術実装案を理解したり、プロジェクトの必要に応じてコラボレーション案を使用したりすることができます.本章では、ソースコードのコンパイルからプロジェクトの使用まで、libcoの入門使用方法を記録しようとします.
説明:プラットフォームの問題のため、実際の操作中に発生する可能性のある問題は本文章の記録とは異なり、自分で分析して解決してください.完全にそのまま運ぶことはできません.
libcoライブラリダウンロードコンパイル
Githubの下から
コンパイルが完了すると、対応する静的ライブラリファイル
新しいLinuxコンソールプロジェクトテストlibco
マルチスレッドプログラミングチュートリアルでは、生産者の消費者問題という古典的な例があります.実際,生産者消費者問題もコラボレーションに最適な応用シーンであるため,今回は生産者消費者シーンを用いてlibcoをテストする.静的ライブラリファイルの開発が便利であるため、今回静的ライブラリを使用してテストを開発するには、まず、プロジェクトディレクトリに直接コピーしてプロジェクトファイルに追加することができ、
1.コンシステントオブジェクトの作成
関数プロトタイプは次のように宣言されます.
パラメータ
2.生産者と消費者の協力実行関数の作成
3.コンシステント実行パラメータを指定する生産者消費者間の通信には、条件変数を使用する必要があり、データへのアクセスに共通プールを使用する必要があるため、コンシステントパラメータは次のように宣言できます.
コプロセッサを作成する前に、パラメータオブジェクトを作成して初期化します.
4.起動コンシステント
パラメータ
5.起動協程イベント処理循環協程作成起動後、
最後に、次のテストコードを作成できます.
リンクのコンパイル
プロジェクトは静的ライブラリを参照するため、
ライブラリファイルのディレクトリを指定し、次にライブラリファイル名を指定します.
確定をクリックすると、プロジェクトをコンパイルしてみて、コンパイルエラーを発見しました.主な情報は以下の通りです.
上記のエラーは主に「undefined reference to“dlsym”」と「undefined reference to“pthread_getspecific”」であり、これはプラットフォームクラスのライブラリリンクエラーであり、コンパイルオプションを調整する必要があり、リンク時に追加オプション
リンクを再コンパイルすると、成功しました.
デバッグ運転
このとき
実行結果により、次のことが判明しました.ライブラリは有効で、私達はマルチスレッド技術を通じていないで、生産者の消費者の運行シーンを実現して、しかも生産後すぐに消費して、遅延がなくて、性能は より良いですテストコードには、1人の生産者、2人の消費者がいますが、実行中は各ロットが1人の消費者で動作しますが、異なるロットは2人の消費者で交互に選択されます.コードを分析すると、 を譲渡することができます.は、同じスレッド内で実行するため、同じ時点で1つのスレッド内の複数のスレッドで1つのスレッドのみが実行されるため、この例では、生産者および消費者はデータにロックアクセスしていないが、依然として安全な である.
プロジェクトアドレス
プロジェクトgithubアドレス
リファレンスドキュメント
テンセント開源協程庫libco-原理と応用
libcoは微信バックグラウンドで大規模に使用されているc/c++コラボレーションライブラリであり、2013年から現在まで微信バックグラウンドの数万台の機器で安定して稼働している.
libcoは、いくつかの関数インタフェースco_のみを介してcreate/co_resume/co_yield再配合co_pollは、スレッドライブラリのように簡単に同期または非同期の書き方をサポートします.同時にライブラリにはsocketファミリー関数のhookが提供されており,バックグラウンド論理サービスは論理コードをほとんど修正することなく非同期化改造を完了できる.
libcoはソースコードが簡潔で効率的なコラボレーションライブラリであり、ソースコードを読むことでコラボレーションの概念と技術実装案を理解したり、プロジェクトの必要に応じてコラボレーション案を使用したりすることができます.本章では、ソースコードのコンパイルからプロジェクトの使用まで、libcoの入門使用方法を記録しようとします.
説明:プラットフォームの問題のため、実際の操作中に発生する可能性のある問題は本文章の記録とは異なり、自分で分析して解決してください.完全にそのまま運ぶことはできません.
libcoライブラリダウンロードコンパイル
Githubの下から
libco
をダウンロードしてコンパイルします.コンパイルは簡単です.直接make
でいいです.以下のようにします.tony:~/code/github$ git clone https://github.com/Tencent/libco.git
Cloning into 'libco'...
remote: Enumerating objects: 256, done.
remote: Total 256 (delta 0), reused 0 (delta 0), pack-reused 256
Receiving objects: 100% (256/256), 180.23 KiB | 151.00 KiB/s, done.
Resolving deltas: 100% (143/143), done.
tony:~/code/github$ cd libco/
tony:~/code/github/libco$ make
xxx xxx
tony:~/code/github/libco$ ls lib/*
lib/libcolib.a
tony:~/code/github/libco$ ls solib/*
solib/libcolib.so
コンパイルが完了すると、対応する静的ライブラリファイル
lib/libcolib.a
と動的ライブラリファイルsolib/libcolib.so
が生成され、後続のプロジェクトコードが使用される場合は、ヘッダファイルco_routine.h
を含めるだけでよい.新しいLinuxコンソールプロジェクトテストlibco
マルチスレッドプログラミングチュートリアルでは、生産者の消費者問題という古典的な例があります.実際,生産者消費者問題もコラボレーションに最適な応用シーンであるため,今回は生産者消費者シーンを用いてlibcoをテストする.静的ライブラリファイルの開発が便利であるため、今回静的ライブラリを使用してテストを開発するには、まず、プロジェクトディレクトリに直接コピーしてプロジェクトファイルに追加することができ、
libco
オープンソースプロジェクトおよび例の説明に従って、使用方法を学習する必要があります.1.コンシステントオブジェクトの作成
//
stCoRoutine_t* pProducerCo = NULL;
// ,
// 0,
co_create(&pProducerCo, NULL, Producer, &p);
関数プロトタイプは次のように宣言されます.
int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg )
パラメータ
stCoRoutine_t
はパラメータで、作成したコヒーレンスオブジェクトパラメータstCoRoutineAttr_t
はパラメータで、作成コヒーレンスの属性を指定します.今回はデフォルトの属性を使用して、空のパラメータroutine
はパラメータで、指定コヒーレンス実行関数パラメータarg
はパラメータで、指定コヒーレンス実行関数のパラメータ2.生産者と消費者の協力実行関数の作成
void* Producer(void* arg);
void* Consumer(void* arg);
co_create
関数によって宣言されたコンシステント実行関数のプロトタイプに従って、生産者と消費者の関数をそれぞれ作成します.コンシステント関数内では、以下のようにコンシステントHOOKを先に有効にする必要があります.void* Producer(void* arg)
{
// HOOK
co_enable_hook_sys();
stPara_t* p = (stPara_t*)arg;
while (true)
{
}
return NULL;
}
3.コンシステント実行パラメータを指定する生産者消費者間の通信には、条件変数を使用する必要があり、データへのアクセスに共通プールを使用する必要があるため、コンシステントパラメータは次のように宣言できます.
struct stPara_t
{
//
stCoCond_t* cond;
//
std::vector<int> vecData;
// ID
int id;
// id
int cid;
};
コプロセッサを作成する前に、パラメータオブジェクトを作成して初期化します.
stPara_t p;
p.cond = co_cond_alloc();
p.cid = p.id = 0;
4.起動コンシステント
co_create
を使用して作成されたコンシステントは実行のために有効ではありません.co_resume
を使用して起動コンシステントを表示する必要があります.関数co_resume
は、次のようにプロトタイプを宣言します.void co_resume(stCoRoutine_t *co)
パラメータ
stCoRoutine_t
は入力パラメータであり、co_create
の出力パラメータであり、この関数は、resume
ではなくstart
であり、現在の出力に実行権限を与えるために使用される.5.起動協程イベント処理循環協程作成起動後、
epoll
のイベント循環処理を実行し、協程のスケジューリングと非同期操作を支援する必要があります.コードは以下の通りです.//
co_eventloop(co_get_epoll_ct(), NULL, NULL);
最後に、次のテストコードを作成できます.
#include
#include
#include
#include
#include
#include "co_routine.h"
void* Producer(void* arg);
void* Consumer(void* arg);
struct stPara_t
{
//
stCoCond_t* cond;
//
std::vector<int> vecData;
// ID
int id;
// id
int cid;
};
int main()
{
stPara_t p;
p.cond = co_cond_alloc();
p.cid = p.id = 0;
srand(time(NULL));
// (CCB), ,
const int nConsumer = 2;
stCoRoutine_t* pProducerCo = NULL;
stCoRoutine_t* pConsumerCo[nConsumer] = { NULL };
//
// 0
co_create(&pProducerCo, NULL, Producer, &p);
co_resume(pProducerCo);
std::cout << "start producer coroutine success" << std::endl;
//
for (int i = 0; i < nConsumer; i++)
{
co_create(&pConsumerCo[i], NULL, Consumer, &p);
co_resume(pConsumerCo[i]);
}
std::cout << "start consumer coroutine success" << std::endl;
//
co_eventloop(co_get_epoll_ct(), NULL, NULL);
return 0;
}
void* Producer(void* arg)
{
// HOOK
co_enable_hook_sys();
stPara_t* p = (stPara_t*)arg;
int cid = ++p->cid;
while (true)
{
//
for (int i = rand() % 5 + 1; i > 0; i--)
{
p->vecData.push_back(++p->id);
std::cout << "[" << cid << "] + add new data:" << p->id << std::endl;
}
//
co_cond_signal(p->cond);
// poll
poll(NULL, 0, 1000);
}
return NULL;
}
void* Consumer(void* arg)
{
// HOOK
co_enable_hook_sys();
stPara_t* p = (stPara_t*)arg;
int cid = ++p->cid;
while (true)
{
// ,
if (p->vecData.empty())
{
co_cond_timedwait(p->cond, -1);
continue;
}
//
std::cout << "[" << cid << "] - del data:" << p->vecData.front() << std::endl;
p->vecData.erase(p->vecData.begin());
}
return NULL;
}
リンクのコンパイル
プロジェクトは静的ライブラリを参照するため、
libcolib.a
ファイルを導入する必要があります.このファイルを導入するには、2つのステップに分けられます.ライブラリファイルのパスを指定します.2.リファレンスライブラリファイル名を指定します.VSでの具体的な操作は以下の通りです.ライブラリファイルのディレクトリを指定し、次にライブラリファイル名を指定します.
確定をクリックすると、プロジェクトをコンパイルしてみて、コンパイルエラーを発見しました.主な情報は以下の通りです.
1>D:\AppData\PerDoc\temp\demo\libco_demo\libcolib.a(co_hook_sys_call.o) : error : In function `__static_initialization_and_destruction_0(int, int) [clone .constprop.28]':
1>/home/tony/code/github/libco/co_hook_sys_call.cpp(107): error : undefined reference to `dlsym'
1>D:\AppData\PerDoc\temp\demo\libco_demo\libcolib.a(co_hook_sys_call.o) : error : /home/tony/code/github/libco/co_hook_sys_call.cpp:109: more undefined references to `dlsym' follow
1>D:\AppData\PerDoc\temp\demo\libco_demo\libcolib.a(co_routine.o) : error : In function `co_getspecific(unsigned int)':
1>/home/tony/code/github/libco/co_routine.cpp(1062): error : undefined reference to `pthread_getspecific'
上記のエラーは主に「undefined reference to“dlsym”」と「undefined reference to“pthread_getspecific”」であり、これはプラットフォームクラスのライブラリリンクエラーであり、コンパイルオプションを調整する必要があり、リンク時に追加オプション
-pthread -Wl,--no-as-needed -ldl
を追加する必要があり、以下のように構成されている.リンクを再コンパイルすると、成功しました.
デバッグ運転
このとき
F5
でデバッグして実行すると、プログラムが正常に実行され、結果は以下の通りです.実行結果により、次のことが判明しました.
libco
のコヒーレンススケジューリングはプログラムによって制御されているため、私たちのコードでは、ある消費者のコヒーレンスが消費を開始すると、データがないまでコヒーレンスを譲渡するので、消費者はデータを消費するたびに生産者にプロジェクトアドレス
プロジェクトgithubアドレス
リファレンスドキュメント
テンセント開源協程庫libco-原理と応用