Multiple Read / Single Writer Class Security

I am working on a set that is often read but rarely written.

class A { boost::shared_ptr<std::set<int> > _mySet; public: void add(int v) { boost::shared_ptr<std::set<int> > tmpSet(new std::set<int>(*_mySet)); tmpSet->insert(v); // insert to tmpSet _mySet = tmpSet; // swap _mySet } void check(int v) { boost::shared_ptr<std::set<int> > theSet = _mySet; if (theSet->find(v) != theSet->end()) { // do something irrelevant } } }; 

In the class add() is called by only one thread, and check() is called by many threads. check() doesn't care if _mySet last or not. Is the class thread safe? Is it possible that the thread executing check() will observe the swap _mySet , occurring before insert to tmpSet ?

+4
source share
3 answers

This is an interesting use of shared_ptr for thread safety. Regardless of whether this is good, it depends on boost::shared_ptr . In particular, does it install some kind of fence or membranes, so that you are guaranteed that all entries in the constructor and insert functions from set are encountered before any pointer value changes.

I can find no guarantee of thread safety in general in the Boost smart pointer documentation. This surprises me, as I was sure there were some. But a quick look at the sources for 1.47.0 does not show, and that any use of boost::shared_ptr in a streaming environment will fail. (Can someone please tell me what I don't see. That boost::shared_ptr ignores streams.)

In any case, there are three possibilities: you cannot use a shared pointer in a streaming environment (which seems to be the case), a shared pointer ensures its internal consistency in a streaming environment, but does not establish order in relation to other objects, or a shared pointer sets a complete order. Only in the latter case will your code be safe as it is. In the first case, you will need some form of blocking everything, and in the second, you will need some kind of fences or membranes to ensure that the necessary notes are actually made before the publication of the new version, and that they will be visible before trying to read it.

+2
source

You need synchronization, it is not thread safe. This usually does not matter, even as simple as shared += value; is not thread safe.

see here, for example, regarding shared_ptr thread safety: Is boost shared_ptr <XXX> a safe thread?

I would also question your distribution / exchange in add() and the use of shared_ptr in check()

update:

I came back and reworked dox for shared_ptr ... Most likely, this is thread safe in your particular case, since link counting for shared_ptr is thread safe. However, you do unnecessary complexity (IMHO) without using read / write locks.

+2
source

In the end, this code should be thread safe:

atomic_store(&_my_set,tmpSet);

and

theSet = atomic_load(&_mySet);

(instead of simple appointments)

But I do not know the current atomicity support status for shared_ptr.

Note that adding atomicity to shared_ptr without locking is really a dificult thing; therefore, even atomicity is implemented, it can transfer muffs or spy blocks to usermode and, therefore, can sometimes suffer from performance problems.

Edit: Perhaps a mutable classifier for the _my_set member variable should also be added .. but I'm not sure if this is strictly required by the semantics of atomic operations

0
source

Source: https://habr.com/ru/post/1395161/


All Articles