Làm sao để gọi hàm thành viên trong class trong thread

Xin chào mọi người, em mới học về thread, em có một chương trình thế này:

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <vector>
#include <functional>
#include <algorithm>
#include <chrono>

template<typename T>
class safe_queue
{
private:
    std::queue<T> m_queue;
    mutable std::mutex m_mutex;
    std::condition_variable m_cond_variable;

public:
    safe_queue()
    {

    }

    safe_queue(const safe_queue& other)
    {
        std::lock_guard<std::mutex> lk(other.m_mutex);
        m_queue = other.m_queue;
    }

    void push(T value)
    {
        std::lock_guard<std::mutex> lk(m_mutex);
        m_queue.push(value);
        m_cond_variable.notify_one();
    }

    void wait_and_pop(T& value)
    {
        std::unique_lock<std::mutex> lk(m_mutex);
        m_cond_variable.wait(lk, [this] { return !m_queue.empty(); });
        value = m_queue.front();
        m_queue.pop();
    }

    std::shared_ptr<T> wait_and_pop()
    {
        std::unique_lock<std::mutex> lk(m_mutex);
        m_cond_variable.wait(lk, [this] { return !m_queue.empty(); });
        std::shared_ptr<T> value = std::make_shared<T>(m_queue.front());
        m_queue.pop();
        return value;
    }

    bool try_pop(T& value)
    {
        std::lock_guard<std::mutex> lk(m_mutex);
        if (m_queue.empty())
            return false;
        value = m_queue.front();
        m_queue.pop();
        return true;
    }

    // std::shared_ptr<T> try_pop()
    // {
    //     std::lock_guard<std::mutex> lk(m_mutex);
    //     if (m_queue.empty())
    //         return NULL;
    //     std::shared_ptr<T> value = std::make_shared<T>(m_queue.front());
    //     m_queue.pop();
    //     return value;
    // }

    bool empty() const
    {
        std::lock_guard<std::mutex> lk(m_mutex);
        return m_queue.empty();
    }
};

void func_try_pop()
{
    auto start = std::chrono::high_resolution_clock::now();

    const unsigned int hardware_concurency = std::thread::hardware_concurrency();

    std::vector<std::thread> threads(hardware_concurency * 2);
    std::vector<int> vals(hardware_concurency);
    safe_queue<int> sq_instance = safe_queue<int>();

    for (int i = 0; i < hardware_concurency; ++ i)
    {
        threads[i] = std::thread(&safe_queue<int>::push, std::ref(sq_instance), i);
        threads[i + hardware_concurency] = std::thread(&safe_queue<int>::try_pop, std::ref(sq_instance), std::ref(vals[i]));
    }

    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));

    auto end = std::chrono::high_resolution_clock::now();

    std::chrono::duration<double, std::milli> ms_double = end - start;

    std::cout << "execution try_pop: " << ms_double.count() << "\n";
}

int main()
{
    func_try_pop();
    return 0;
}

Em đã biết cách để gọi hàm trong class cho thread, nhưng khi em mở code block try_pop đang bị comment (overloading), thì chương trình bị lỗi.
Nó thông báo lỗi thế này ạ:

Em muốn hỏi trong trường hợp sử dụng hàm try_pop như trên thì làm sao để gọi hàm trong thread để lấy hàm thứ nhất ạ, em xin cảm ơn mọi người.

Đừng quá tin vào những gì VSCode nói là được, bởi vì nó không phải là compiler nên chuyện nó nói sai là bình thường. Bao giờ bạn biên dịch và chạy bị lỗi thì hãy lo nha. Link chứng minh code kia chạy hoàn toàn bình thường: https://wandbox.org/permlink/tVBKXXXN6nB8ibNK

4 Likes

Ko ạ, ý em là, đoạn code trên hoàn toàn bình thường, nếu comment function

// std::shared_ptr<T> try_pop()
    // {
    //     std::lock_guard<std::mutex> lk(m_mutex);
    //     if (m_queue.empty())
    //         return NULL;
    //     std::shared_ptr<T> value = std::make_shared<T>(m_queue.front());
    //     m_queue.pop();
    //     return value;
    // }

Nếu mở nó ra thì nó bị báo lỗi ấy anh.

À, sorry, mình đọc không kỹ, nhưng mà lần sau tốt hơn bạn nên để sẵn code có lỗi để đỡ tốn công sức nha bạn.
Về vấn đề overload này, suy nghĩ logic 1 chút thì ngay khi bạn lấy &safe_queue<int>::try_pop để truyền cho std::thread thì compiler hoàn toàn không biết tham số là gì để nó lựa chọn cả => dẫn tới lỗi

=> Solution là dùng static_cast/lambda/std::mem_fn để ép kiểu của cái try_pop về đúng overload mà mình cần: https://wandbox.org/permlink/vqcfZIXc1XfSK1qL

6 Likes

Dạ vâng, em hiểu rồi, cảm ơn anh nhiều :grin:

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?