Использование 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
функция. Ни в том случае, если такая функция не возвращается немедленно, ни может задержать, пока флаг не будет заблокирован.
Также для меня загадка, как получить механизм блокировки с такой функцией, которая всегда устанавливает значение и возвращает предыдущее значение. без возможности читать только фактические настройки.
Любые предложения приветствуются.
Между прочим, процесс, вовлеченный в один из потоков, является очень длинным запросом к базе данных, которая получает много строк, и мне нужно только приостановить его в определенной зоне кода, где происходит столкновение (при обработке каждой строки), и я не могу дождитесь завершения потока, чтобы завершить 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;
}
Похоже, вы пытаетесь написать спинлок. Да, вы можете сделать это с std::atomic_flag
, но вам лучше использовать std::mutex
вместо. Не используйте атомики, если вы действительно не знаете, что делаете.
Чтобы действительно ответить на заданный вопрос: Да, вы можете использовать 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_;
};