首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11(14/17/20)线程管理

C++11(14/17/20)线程管理
EN

Code Review用户
提问于 2021-10-28 15:34:03
回答 1查看 159关注 0票数 3

在现代C++中,我正在实现线程管理员。我所得到的是有用的,虽然它还没有按照我想要的方式组织起来,但我想要一些关于基本面的反馈。提前感谢您的所有提示。=)

所有线程(包括main()以向程序结束发送信号)都通过以下方式共享数据:

代码语言:javascript
复制
#ifndef SHAREDDATA_HPP
#define SHAREDDATA_HPP

#include <condition_variable>
#include <thread>

class SharedData {
    public:
        std::mutex              keypress_mutex;
        std::condition_variable keypress_cv;
        bool                    keypress_flag;

        std::mutex              thread_count_mutex;
        std::condition_variable thread_count_cv;
        unsigned int            thread_count;

        std::mutex              thread_kill_mutex;
        std::condition_variable thread_kill_cv;
        bool                    thread_kill_flag;

        SharedData():
            keypress_flag{false},
            thread_count{0},
            thread_kill_flag{false}
        { }
        ~SharedData() = default;
};

#endif // SHAREDDATA_HPP

然后我们找了个小RAII来帮助跟踪线程数:

代码语言:javascript
复制
#ifndef THREADCOUNTER_HPP
#define THREADCOUNTER_HPP

#include <thread>

class SharedData;

class ThreadCounter {
    public:
        explicit ThreadCounter(SharedData *share);
        ~ThreadCounter();
    private:
        SharedData         *_share;
};

#endif // THREADCOUNTER_HPP


//--------------------------


#include "ThreadCounter.hpp"

#include "SharedData.hpp"

ThreadCounter::ThreadCounter(SharedData *share) :
    _share{share}
{
    std::lock_guard<std::mutex> _lock(_share->thread_count_mutex);
    share->thread_count++;
}

ThreadCounter::~ThreadCounter() {
    std::lock_guard<std::mutex> _lock(_share->thread_count_mutex);
    _share->thread_count--;

    if(_share->thread_count == 0) {
        _share->thread_count_cv.notify_one();
    }
}

接下来,ManagedThread类本身:

代码语言:javascript
复制
#ifndef MANAGEDTHREAD_HPP
#define MANAGEDTHREAD_HPP

#include <thread>

class SharedData;

class ManagedThread {
    public:
        void launch();

        explicit ManagedThread(SharedData *share);
        ~ManagedThread();
        ManagedThread() = delete;

        void operator()();

    private:
        SharedData *_share;
        std::thread _thread;
};

#endif // MANAGEDTHREAD_HPP


//--------------------------


#include "ManagedThread.hpp"

#include "SharedData.hpp"
#include "ThreadCounter.hpp"

#include <chrono>
#include <iostream>
#include <cassert>

using namespace std::chrono_literals;

void ManagedThread::launch() {
    if(!_thread.joinable()) {
        _thread = std::thread(std::ref(*this));
    }
    else {
        assert((false) && "Managed Thread not launchable!");
    }
}

ManagedThread::ManagedThread(SharedData *share) :
    _share{share},
    _thread{std::thread()}
{ }

ManagedThread::~ManagedThread() {
    if(_thread.joinable()) {
        _thread.join();
    }
}

void ManagedThread::operator()() {
    ThreadCounter tc(_share);
    while(true) {
        std::this_thread::sleep_for(250ms);
        std::cout << "Whee!" << std::endl;

        std::unique_lock<std::mutex> kill_lock(_share->thread_kill_mutex);
        if(_share->thread_kill_cv.wait_for(kill_lock, 100ms,
                [&](){ return _share->thread_kill_flag; })) {
            break;
        }
    }
}

以及负责清理协调的ThreadManager

代码语言:javascript
复制
#ifndef THREADMANAGER_HPP
#define THREADMANAGER_HPP

class SharedData;

class ThreadManager {
    public:
        explicit ThreadManager(SharedData *share) : _share{share} { };
        ~ThreadManager() = default;

        void operator()();

    private:
        SharedData *_share;
};

#endif // THREADMANAGER_HPP


//--------------------------

#include "ThreadManager.hpp"

#include "SharedData.hpp"

#include <chrono>

using namespace std::chrono_literals;

void ThreadManager::operator()() {
    std::this_thread::sleep_for(25ms);

    std::unique_lock<std::mutex> keypress_lock(_share->keypress_mutex);
    _share->keypress_cv.wait(keypress_lock,
                            [&](){ return _share->keypress_flag; });
    keypress_lock.unlock();

    {
        std::lock_guard<std::mutex> kill_lock(_share->thread_kill_mutex);
        _share->thread_kill_flag = true;
    }
    _share->thread_kill_cv.notify_all();

    std::unique_lock<std::mutex> count_lock(_share->thread_count_mutex);
    _share->thread_count_cv.wait(count_lock,
                                [&](){ return _share->thread_count == 0; });
}

最后,一个main.cpp把它连接在一起。

代码语言:javascript
复制
#include "SharedData.hpp"
#include "ThreadManager.hpp"
#include "ManagedThread.hpp"

#include <iostream>
#include <future>

int main() {
    SharedData share;
    ThreadManager tm(&share);
    ManagedThread t0(&share);

    t0.launch();

    std::future<void> cf = std::async(std::launch::async, std::move(tm));

    int input;
    std::cin >> input;
    {
        std::lock_guard<std::mutex> lock(share.keypress_mutex);
        share.keypress_flag = true;
    }
    share.keypress_cv.notify_one();
    cf.get();

    return 0;
}

我知道我不喜欢的是ThreadManager并不拥有SharedData。我还希望ThreadManager能够泛化地管理继承的线程中的任何ManagedThread,甚至可能是重载的operator(),这样可调用的线程可以做任何事情,但仍然是“管理”的。

在这一点上,这些只是思考--我真正想知道的是,到目前为止,这个系统实现得有多好或有多差。=)

再次感谢您的反馈,我期待着改进这个设置并在将来利用它。

EN

回答 1

Code Review用户

发布于 2021-10-28 18:23:39

通过引用传递参数

您正在通过指针传递SharedData。如果通过引用来传递它的话会更干净:

代码语言:javascript
复制
class ThreadCounter {
public:
    explicit ThreadCounter(SharedData& share);
    ~ThreadCounter();
private:
    SharedData& _share;
};

使用原子变量而不是lock.

当您只需使用原子变量时,锁定是昂贵和过于复杂的:

代码语言:javascript
复制
struct SharedData
{
    std::atomic<bool> keypress_flag = false;
}

int main() {
    SharedData share;
    // start threads
    int input;
    std::cin >> input;
    share.keypress_flag = true;
    // join threads
}

不使用std::endl

std::endl刷新输出。您不必使用\n

代码语言:javascript
复制
std::cout << "Whee!\n";

最后的想法

我不太清楚你想做什么。在我看来,您可以用以下简单的内容替换所有代码:

代码语言:javascript
复制
#include <atomic>
#include <iostream>
#include <thread>

std::atomic_bool running = true;

void func()
{
    using namespace std::chrono_literals;
    while (running)
    {
        std::this_thread::sleep_for(250ms);
        std::cout << "Whee!\n";
    }
}

int main()
{
    std::thread thread(func);
    int input;
    std::cin >> input;
    running = false;
    thread.join();
}
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/269462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档