boost — возможно ли получить механизм блокировки потоков в C ++ с помощью std :: atomic_flag?

Использование MS Visual C ++ 2012

У класса есть член типа std::atomic_flag

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

Есть объект типа А

A object;

кто может получить доступ к двум (Boost) потокам

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

Идея состоит в том, чтобы подождать поток, если к объекту обращается другой поток.

Вопрос: возможно ли построить такой механизм с atomic_flag объект? Не скажу, что на данный момент я хочу немного облегченного, что boost :: mutex.

Между прочим, процесс, вовлеченный в один из потоков, является очень длинным запросом к базе данных, которая получает много строк, и мне нужно только приостановить его в определенной зоне кода, где происходит столкновение (при обработке каждой строки), и я не могу дождаться окончания всей цепочки 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 функция. Ни в том случае, если такая функция не возвращается немедленно, ни может задержать, пока флаг не будет заблокирован.

Также для меня загадка, как получить механизм блокировки с такой функцией, которая всегда устанавливает значение и возвращает предыдущее значение. без возможности читать только фактические настройки.

Любые предложения приветствуются.

2

Решение

Между прочим, процесс, вовлеченный в один из потоков, является очень длинным запросом к базе данных, которая получает много строк, и мне нужно только приостановить его в определенной зоне кода, где происходит столкновение (при обработке каждой строки), и я не могу дождитесь завершения потока, чтобы завершить 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;
}
8

Другие решения

Похоже, вы пытаетесь написать спинлок. Да, вы можете сделать это с std::atomic_flag, но вам лучше использовать std::mutex вместо. Не используйте атомики, если вы действительно не знаете, что делаете.

2

Чтобы действительно ответить на заданный вопрос: Да, вы можете использовать std :: atomic_flag для создания объекта блокировки потока, называемого спин-блокировкой.

#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_;
};
1