본문 바로가기
프로그래밍/C & C++

intel tbb::concurrent_queue를 이용해보기

by 체리 2022. 1. 9.
반응형

ubuntu에서는 아래와 같이 설치 필요

* 직접 github에서 받아도 되나 편리한걸 쓰자

sudo apt install libtbb-dev

build는 요런식으로..

g++ concurrent_queue.cpp -pthread -ltbb -std=c++14

 

stl::queue와 mutex를 이용한 queue와 tbb::concurrent_queue의 비교

MAX개(1,000,000)의 Entry class를 push하는 thread를 1, 2, 4개씩, pop 하는 1개의 thread를 생성하여 시간 측정

 

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
#include <queue>
#include <functional>
#include <tbb/concurrent_queue.h>

using namespace std;
using std::chrono::system_clock;
using std::chrono::duration;

class Entry
{
public:
    Entry(uint64_t id) : id_(id)
    {
    }

private:
    uint64_t id_;
};

class Queue
{
public:
    Queue() = default;
    virtual void Push(shared_ptr<Entry> item) = 0;
    virtual shared_ptr<Entry> Pop() = 0;
};

class StlQueue : public Queue
{
public:
    StlQueue() = default;
    void Push(shared_ptr<Entry> item) override
    {
        std::lock_guard<mutex> lock(lock_);
        q_.push(item);
    }

    shared_ptr<Entry> Pop() override
    {
        if (!q_.size())
            return nullptr;

        std::lock_guard<mutex> lock(lock_);
        shared_ptr<Entry> t = q_.front();
        q_.pop();

        return t;
    }

private:
    queue<shared_ptr<Entry>> q_;
    mutex lock_;
};

class TbbQueue : public Queue
{
public:
    TbbQueue() = default;
    void Push(shared_ptr<Entry> item) override
    {
        q_.push(item);
    }

    shared_ptr<Entry> Pop() override
    {
        shared_ptr<Entry> t;
        if (!q_.try_pop(t))
            return nullptr;
        return t;
    }

private:
    tbb::concurrent_queue<shared_ptr<Entry>> q_;
};

static const uint64_t MAX = 1000000;

void p_thread(Queue& queue, uint64_t count)
{
    while (count != 0)
    {
        queue.Push(make_shared<Entry>(count));
        count--;
    }
}

void c_thread(Queue& queue, uint64_t count)
{
    while (count != 0)
    {
        auto i = queue.Pop();
        if (i == nullptr)
            continue;
        count--;
    }
}

void Run(Queue& q, int t_count)
{
    cout << typeid(q).name() << " thread count: " << t_count << endl;
    auto start = system_clock::now();

    vector<thread> v;
    thread c1(c_thread, std::ref(q), MAX);

    for (int i = 0; i < t_count; ++i)
        v.emplace_back(thread(p_thread, std::ref(q), MAX / t_count));

    for (auto& t : v)
        t.join();
    c1.join();

    auto end = system_clock::now();
    cout << "elpased " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms" << endl;
}

int main()
{
    TbbQueue q1;
    Run(q1, 1);
    Run(q1, 2);
    Run(q1, 4);

    StlQueue q2;
    Run(q2, 1);
    Run(q2, 2);
    Run(q2, 4);

    return 0;
}
반응형

댓글