admin管理员组

文章数量:1355731

Has counting_semaphore<X>::acquire() a barrier so that I won't need to have an atomic_thread_fence( memory_order_acquire ). The same would be nice for counting_semaphore<X>::relese( n ), which should include an atomic_thread_fence( memory_order_release ).

Has counting_semaphore<X>::acquire() a barrier so that I won't need to have an atomic_thread_fence( memory_order_acquire ). The same would be nice for counting_semaphore<X>::relese( n ), which should include an atomic_thread_fence( memory_order_release ).

Share Improve this question edited Mar 31 at 17:24 Nate Eldredge 59.4k6 gold badges71 silver badges113 bronze badges asked Mar 31 at 16:18 Edison von MyosotisEdison von Myosotis 6974 silver badges10 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 5

These functions are acquire and release operations. They contain acquire and release barriers in the sense that acquire() will not be reordered with loads and stores that appear later in program order, and release() will not be reordered with loads and stores that appear earlier.

So for instance, if you do

int x;
std::counting_semaphore sem{0};
int not_atomic;
// thread 1
not_atomic = 47;
sem.release();
// thread 2
sem.acquire();
cout << non_atomic;

then this program does not have a data race, and it is guaranteed to print 47.

This is implied by [thread.sema.cnt p10] (N4860), which says about release():

Synchronization: Strongly happens before invocations of try_acquire that observe the result of the effects.

This also carries over to acquire and try_acquire_for, whose operations are defined as if by calling try_acquire.


However, this is not equivalent to placing a fence. For instance, a release fence would also prevent earlier loads and stores from being reordered with any later stores, not just with the sem.release() itself. Consider for instance

std::atomic<bool> flag{false};
// thread 1
not_atomic = 47;
std::atomic_thread_fence(std::memory_order_release);
flag.store(true, std::memory_order_relaxed);
// thread 2
if (flag.load(std::memory_order_acquire))
    cout << not_atomic;

This program is also free of data races and must print 47. But if you replace it with

// thread 1
not_atomic = 47;
sem.release();
flag.store(true, std::memory_order_relaxed);
// thread 2
if (flag.load(std::memory_order_acquire))
    cout << not_atomic;

then you have a data race. The relaxed store of flag can be reordered above sem.release(), at which point it can then be reordered above not_atomic = 47.

本文标签: cHas countingsemaphoreltXgtacquire a barrierStack Overflow