asio 소스 코드를 읽을 때 암시 적 스트랜드가 만들어 지더라도 스레드간에 동기화 된 데이터를 만드는 방법에 대해 궁금합니다.asio 암시 적 스트랜드 및 데이터 동기화
io_service :: 실행
mutex::scoped_lock lock(mutex_);
std::size_t n = 0;
for (; do_run_one(lock, this_thread, ec); lock.lock())
if (n != (std::numeric_limits<std::size_t>::max)())
++n;
return n;
io_service :: do_run_one의 do_run_one에서
while (!stopped_)
{
if (!op_queue_.empty())
{
// Prepare to execute first handler from queue.
operation* o = op_queue_.front();
op_queue_.pop();
bool more_handlers = (!op_queue_.empty());
if (o == &task_operation_)
{
task_interrupted_ = more_handlers;
if (more_handlers && !one_thread_)
{
if (!wake_one_idle_thread_and_unlock(lock))
lock.unlock();
}
else
lock.unlock();
task_cleanup on_exit = { this, &lock, &this_thread };
(void)on_exit;
// Run the task. May throw an exception. Only block if the operation
// queue is empty and we're not polling, otherwise we want to return
// as soon as possible.
task_->run(!more_handlers, this_thread.private_op_queue);
}
else
{
std::size_t task_result = o->task_result_;
if (more_handlers && !one_thread_)
wake_one_thread_and_unlock(lock);
else
lock.unlock();
// Ensure the count of outstanding work is decremented on block exit.
work_cleanup on_exit = { this, &lock, &this_thread };
(void)on_exit;
// Complete the operation. May throw an exception. Deletes the object.
o->complete(*this, ec, task_result);
return 1;
}
}
를 뮤텍스의 잠금 해제 모든 이전에 실행되는 핸들러 : 다음은 ASIO 코드입니다. 암시 적 스트랜드가있는 경우 핸들러는 동시 실행되지 않지만 문제는 스레드 A가 데이터를 수정하는 핸들러를 실행하고 스레드 B는 스레드 A가 수정 한 데이터를 읽는 다음 핸들러를 실행합니다. 뮤텍스 , 스레드 B가 스레드 A가 만든 데이터의 변경을 어떻게 보았습니까? 핸들러 실행 이전에 뮤텍스 잠금을 해제해도 쓰레드 간의 관계는 액세스 한 핸들러의 데이터에 액세스하지 못합니다. 내가 더 갈 때, 핸들러 실행이 일이라고 fenced_block 사용
completion_handler* h(static_cast<completion_handler*>(base));
ptr p = { boost::addressof(h->handler_), h, h };
BOOST_ASIO_HANDLER_COMPLETION((h));
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_));
p.h = boost::addressof(handler);
p.reset();
// Make the upcall if required.
if (owner)
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
boost_asio_handler_invoke_helpers::invoke(handler, handler);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
이 무엇을? 울타리가 C++ 11에서 지원하는 싱크 프리미티브처럼 보이지만이 펜스는 완전히 asio 자체에 의해 작성됩니다. 이 fenced_block이 데이터 동기화 작업을 수행하는 데 도움이됩니까?
업데이트]
내가 ASIO 실제로 그 핸들러 (speed difference on x86를) 완료 실행까지 잠금을 해제보다 더 빠른 스레드에서 데이터를 동기화 원시 메모리 울타리를 사용 구글과 this 및 this을 읽은 후. 사실 자바 휘발성 키워드는 쓰기 전에 쓰기 메모리 장벽에 의해 구현됩니다. & 전에이 변수를 읽어서 happen-before 관계를 만듭니다.
단순히 누군가가 메모리 펜스 구현을 설명하거나 내가 놓쳤거나 오해 한 것을 추가 할 수 있다면 받아 들일 것입니다.
스레드 A 및 B 문제로 이해할 수없는 것을 자세히 설명 할 수 있습니까? 핸들러가 스트랜드 (암시 적 또는 명시 적)를 통해 실행 중일 때 동시성이 발생하지 않으면 스레드 A가 X를 수정하면 스레드 A 이후에 실행되는 스레드 B가 X에 대한 변경을 관찰하지 못하는 이유는 무엇입니까? 뮤텍스는 동시성이없는 경우 아무런 이점도 제공하지 않습니다. –
이것은 가시성 문제이며 Java 메모리 모델에서 명확하게 정의되었습니다. C++에는 그런 것 (잘 정의 된 메모리 모델)이 없지만 이것은 CPU의 특성이기 때문에 쓰레드 캐시 때문에 동일하다고 생각합니다. 스레드 수정 데이터는 고유 한 영역 (CPU 캐시)에 캐시 된 복사본을 수정하지만 주 메모리는 그대로 유지합니다. 동기화가 없다면 스레드 B는 CPU 캐시가 메인 메모리로 플러시되는지 여부에 따라이 업데이트 된 값을 보거나 보지 못할 수도 있습니다. 하지만 C++에서는 가시성 문제라는 것이 없습니다. 변수를 쓰거나 읽을 때마다 잠금을 사용합니다. – jean