Question

Using MS Visual C++2012

A class has a member of type std::atomic_flag

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

There is an object of type A

A object;

who can be accessed by two (Boost) threads

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

The idea is wait the thread if the object is being accessed by the other thread.

The question is: do it is possible construct such mechanism with an atomic_flag object? Not to say that for the moment, I want some lightweight that a boost::mutex.

By the way the process involved in one of the threads is very long query to a dBase who get many rows, and I only need suspend it in a certain zone of code where the collision occurs (when processing each row) and I can't wait the entire thread to finish join().

I've tryed in each thread some as:

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  */
}

But with no success, because the second thread hangs. In fact, I don't completely understand the mechanism involved in the atomic_flag_test_and_set_explicit function. Neither if such function returns inmediately or can delay until the flag can be locked.

Also it is a mistery to me how to get a lock mechanism with such a function who always set the value, and return the previous value. with no option to only read the actual setting.

Any suggestion are welcome.

Was it helpful?

Solution

By the way the process involved in one of the threads is very long query to a dBase who get many rows, and I only need suspend it in a certain zone of code where the collision occurs (when processing each row) and I can't wait the entire thread to finish join().

Such a zone is known as the critical section. The simplest way to work with a critical section is to lock by mutual exclusion.

The mutex solution suggested is indeed the way to go, unless you can prove that this is a hotspot and the lock contention is a performance problem. Lock-free programming using just atomic and intrinsics is enormously complex and cannot be recommended at this level.

Here's a simple example showing how you could do this (live on 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;
}

OTHER TIPS

It looks like you're trying to write a spinlock. Yes, you can do that with std::atomic_flag, but you are better off using std::mutex instead. Don't use atomics unless you really know what you're doing.

To actually answer the question asked: Yes, you can use std::atomic_flag to create a thread locking object called a 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_;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top