首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用atomic<T>

正确使用atomic<T>
EN

Stack Overflow用户
提问于 2016-05-09 07:52:52
回答 1查看 161关注 0票数 2

目前,我正在为基于C++11线程池类的https://github.com/nbsdx/ThreadPool线程池类为原子变量编写无锁代码。这是我修改过的课程:

代码语言:javascript
复制
class ThreadPool
{
public:
    explicit ThreadPool(int threadCount) :
        _jobsLeft(0),
        _bailout(false)
    {
        _threads = std::vector<std::thread>(threadCount);
        for (int index = 0; index < threadCount; ++index)
        {
            _threads[index] = std::move(std::thread([this]
                {
                    this->Task();
                }));
        }
    }

    void AddJob(std::function<void(void)> job)
    {
        {
            std::lock_guard<std::mutex> lock(_queueMutex);
            _queue.emplace(job);
        }
        {
            std::lock_guard<std::mutex> lock(_jobsLeftMutex);
            ++_jobsLeft;
        }
        _jobAvailableVar.notify_one();
    }

    void JoinAll()
    {
        if (!_bailout)
        {
            _bailout = true;
            _jobAvailableVar.notify_all();
            for (auto& x : _threads)
            {
                if (x.joinable())
                {
                    x.join();
                }
            }
        }
    }

    void WaitAll()
    {
        std::unique_lock<std::mutex> lock(_jobsLeftMutex);
        if (_jobsLeft > 0)
        {
            _waitVar.wait(lock, [this]
                          {
                              return _jobsLeft == 0;
                          });
        }
    }

private:
    void Task()
    {
        while (!_bailout)
        {
            std::function<void(void)> job;
            {
                std::unique_lock<std::mutex> lock(_queueMutex);
                _jobAvailableVar.wait(lock, [this]
                                      {
                                          return _queue.size() > 0 || _bailout;
                                      });
                if (_bailout)
                {
                    return;
                }
                job = _queue.front();
                _queue.pop();
            }
            job();
            {
                std::lock_guard<std::mutex> lock(_jobsLeftMutex);
                --_jobsLeft;
            }
            _waitVar.notify_one();
        }
    }

    std::vector<std::thread> _threads;
    std::queue<std::function<void(void)>> _queue;
    int _jobsLeft;
    std::atomic<bool> _bailout;
    std::condition_variable _jobAvailableVar;
    std::condition_variable _waitVar;
    std::mutex _jobsLeftMutex;
    std::mutex _queueMutex;
};

我对以下各点感到困惑,并希望得到任何建议:

  • 如何使_bailout的使用真正具有原子性?我玩过atomic_flag,但在这种情况下无法让它工作。
  • 是否有可能使_jobsLeft在没有所有这些锁的情况下使用atomic<int>正确运行?我在原始线程池中遇到了一个问题,在很少情况下,WaitAll()无法正确返回。它现在工作得很好,但我觉得它浪费了性能。

编辑:使用普通锁的最终版本可在这里获得:https://github.com/stfx/ThreadPool2

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-09 08:37:33

看看原子方法:http://en.cppreference.com/w/cpp/atomic/atomic

您应该使用load方法原子地读取该值。但是,请注意,以下不是原子的。

代码语言:javascript
复制
if (!_bailout)
{
    _bailout = true;

有一种方法可以执行这些比较和值交换。参见compare_exchange_weak方法。对于jobCount,您可以使用原子。++-是原子的.

但是,请注意,原子只是一个方法调用,调用后的情况可能会发生变化。您仍然需要一个同步队列,为此您需要一个锁。它不需要是一个标准的OS锁,您可以使用原子变量创建一个锁(使用存储和方法)。请参阅以下帖子:https://webkit.org/blog/6161/locking-in-webkit/

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37110370

复制
相关文章

相似问题

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