简体   繁体   中英

any way to implement multi-threaded access to a value without requiring readers to lock

I'm trying to implement a minimalistic synchronization mechanism where there's an object contains some value of type Foo , this Foo may potentially be a heavyweight type, but rarely changes its value. the object may be accessed from multiple threads, almost 100% reads.

I am trying to think of a way to make this work without any locking requirements on the readers. My first attempt was to have my class contain the Foo through a shared pointer member of type std::shared_ptr<Foo> . The read operations would simply copy-construct the shared pointer, dereference it, and then use this "version" of the value to do whatever they want.

The write operations are supposed to apply their changes into a new copy of Foo, and once done, attempt to replace the current version of Foo with a new one.

I realized this is not possible with shared_ptr<Foo> since the copy-constructor could get into a read/write race with something trying to update it, and read a corrupted value. I could get around this problem using boost::intrusive_ptr<Foo> with an atomic counter and doing the version update with a CAS operation, but there's still a race condition I can't get rid of: the reader can be suspended just before calling intrusive_ptr_add_ref on an instance that's about to get destroyed by another thread that lowered the count to 0.

It seems like something is fundamentally broken with this approach.

Is there any way to accomplish this that doesn't rely on a critical section, readers/writer lock or a full-blown RCU (read-copy-update)? Maybe I'm missing something simple. Platform is Win7+/x86/x64.

The solution is to first have a local std::shared_ptr<Foo> which has the new Foo and assign it to the global std::shared_ptr via atomic assignment methods. To clarify: Don't use plain assignment. From the link, you could use:

atomic_store( &global_ptr, std::make_shared<Foo>(...) );

This would work..

Foo * globalFoo;
.
.

Foo* newFoo = new Foo();
Foo* temp;
do {
    temp = globalFoo;
} while(! std::atomic_compare_exchange_weak(temp, globalFoo, newFoo));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM