是否可以使用std :: atomic_flag在C ++中获得线程锁定机制?

时间:2012-10-10 18:41:19

标签: c++ boost c++11 boost-thread atomicity

使用MS Visual C ++ 2012

一个类的成员类型为std::atomic_flag

class A {
    public:
    ...
    std::atomic_flag lockFlag;
    A () { std::atomic_flag_clear (&lockFlag); } 
};

有一个A类型的对象

A object;

谁可以被两个(Boost)线程访问

void thr1(A* objPtr) { ... }
void thr2(A* objPtr) { ... }

如果另一个线程正在访问该对象,那么想法就是等待线程。

问题是:是否有可能使用atomic_flag对象构建此类机制?不是说暂时,我想要一些轻量级的boost :: mutex。

顺便说一下,其中一个线程涉及的进程是非常长的查询到获得很多行的dBase,我只需要在发生冲突的某个代码区域(当处理每一行时)暂停它而我不能等待整个线程完成join()

我在每个帖子中尝试了一些:

thr1 (A* objPtr) {
    ...
    while (std::atomic_flag_test_and_set_explicit (&objPtr->lockFlag, std::memory_order_acquire)) {
        boost::this_thread::sleep(boost::posix_time::millisec(100));
    }
    ...  /* Zone to portect */

    std::atomic_flag_clear_explicit (&objPtr->lockFlag, std::memory_order_release);
    ...  /* the process continues  */
}

但没有成功,因为第二个线程挂起。实际上,我并不完全理解atomic_flag_test_and_set_explicit函数中涉及的机制。如果这样的函数不能立即返回,或者可以延迟直到可以锁定标志。

对我来说,如何获得一个具有这样一个总是设置值的函数的锁机制并返回之前的值也是一种谜。没有选项只能读取实际设置。

欢迎任何建议。

3 个答案:

答案 0 :(得分:8)

  

顺便说一下,其中一个线程涉及的进程是一个非常长的查询到获得很多行的dBase,我只需要在发生冲突的某个代码区域中挂起它(当处理每一行时) )我不能等待整个线程完成join()。

这样的区域称为关键部分。处理关键部分的最简单方法是通过互斥锁定。

建议的互斥解决方案确实是可行的方法,除非您证明这是一个热点并且锁争用是一个性能问题。 使用原子和内在函数的无锁编程非常复杂,不能在此级别推荐。

这是一个简单的示例,说明如何执行此操作(实时http://liveworkspace.org/code/6af945eda5132a5221db823fa6bde49a):

#include <iostream>
#include <thread>
#include <mutex>

struct A
{
    std::mutex mux;
    int x;

    A() : x(0) {}
};

void threadf(A* data)
{
    for(int i=0; i<10; ++i)
    {
        std::lock_guard<std::mutex> lock(data->mux);
        data->x++;
    }
}

int main(int argc, const char *argv[])
{
    A instance;
    auto t1 = std::thread(threadf, &instance);
    auto t2 = std::thread(threadf, &instance);

    t1.join();
    t2.join();

    std::cout << instance.x << std::endl;

    return 0;
}

答案 1 :(得分:2)

看起来你正试图写一个自旋锁。是的,您可以使用std::atomic_flag执行此操作,但最好使用std::mutex。除非你真的知道你在做什么,否则不要使用原子。

答案 2 :(得分:1)

要实际回答问题:是的,您可以使用std :: atomic_flag创建一个名为spinlock的线程锁定对象。

#include <atomic>

class atomic_lock
{
    public:
        atomic_lock()
            : lock_( ATOMIC_FLAG_INIT )
        {}

        void lock()
        {
            while ( lock_.test_and_set() ) { } // Spin until the lock is acquired.
        }

        void unlock()
        {
            lock_.clear();
        }

    private:
        std::atomic_flag lock_;
};