コラボレーションライブラリlibco学習の使用例

26573 ワード

概要
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でデバッグして実行すると、プログラムが正常に実行され、結果は以下の通りです.
実行結果により、次のことが判明しました.
  • ライブラリは有効で、私達はマルチスレッド技術を通じていないで、生産者の消費者の運行シーンを実現して、しかも生産後すぐに消費して、遅延がなくて、性能は
  • より良いです
  • テストコードには、1人の生産者、2人の消費者がいますが、実行中は各ロットが1人の消費者で動作しますが、異なるロットは2人の消費者で交互に選択されます.コードを分析すると、libcoのコヒーレンススケジューリングはプログラムによって制御されているため、私たちのコードでは、ある消費者のコヒーレンスが消費を開始すると、データがないまでコヒーレンスを譲渡するので、消費者はデータを消費するたびに生産者に
  • を譲渡することができます.
  • は、同じスレッド内で実行するため、同じ時点で1つのスレッド内の複数のスレッドで1つのスレッドのみが実行されるため、この例では、生産者および消費者はデータにロックアクセスしていないが、依然として安全な
  • である.
    プロジェクトアドレス
    プロジェクトgithubアドレス
    リファレンスドキュメント
    テンセント開源協程庫libco-原理と応用