1

For example, I have this class:

class Example
{
public: 
    static int m_test;
}

I have threads A and B both using this static member variable. Is this member variable thread safe somewhere under the hub?

I would assume it is not, since it is statically allocated and therefore both threads would be accessing the same memory location, possibly causing collisions. Is that correct or there is some hidden mechanism that makes this static member thread-safe?

omegasbk
  • 826
  • 1
  • 10
  • 24
  • Depends on what operations you want to do with it. Usually just reading is a single operation. Also writing is a single operation. It gets tricky when you do this for example: `m_test++`. – Neijwiert Jan 18 '19 at 09:45
  • not thread safe – Gojita Jan 18 '19 at 09:45
  • Yeah, I assumed so. Thanks! – omegasbk Jan 18 '19 at 09:46
  • 1
    @Neijwiert Reading is not necessary a single operation. And even when it indeed is it does not mean that this operation is thread-safe. – user7860670 Jan 18 '19 at 09:47
  • @Neijwiert By _single operation_ you likely mean an _atomic operation_? There is no guarantee in the Standard that stores/loads are atomic for ordinary variables. They are, on some architectures, but not generally. – Daniel Langr Jan 18 '19 at 09:48
  • As the duplicate answers - It is thread safe : If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. – Robert Andrzejuk Jan 18 '19 at 09:54
  • 1
    @RobertAndrzejuk I don't think it's a duplicate. This question is not about initialization of `Example::m_test`, it's about its usage from within threads, which may include it's update. – Daniel Langr Jan 18 '19 at 09:55
  • @DanielLangr That's why I specified "Usually". – Neijwiert Jan 18 '19 at 09:56
  • 1
    @Neijwiert Yes, but we usually do not write programs that "usually" work :). BTW, even if you are sure that the program will be run on an architecture where loads/stores are atomic, without any kind of synchronization (mutextes, atomic variables, memory fences, ...) you would have no guarantee that the updated value would be "seen" by other threads. A compiler may even optimize out such a write completely. – Daniel Langr Jan 18 '19 at 10:01
  • 1
    Ok. But I think it is relevant that initialization is thread safe, which is not mentioned in the answers : https://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11. – Robert Andrzejuk Jan 18 '19 at 10:08

2 Answers2

2

No it is not thread safe insofar there is no built-in mechanism to obviate data races.

static std::atomic<int> m_test; would be though.

Note that you also have thread_local as a storage duration too - not of use to you in this instance - but if you had that rather than static then every thread would get their own m_test.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • I believe it is thread-safe if the variable is only read by both threads, right? http://eel.is/c++draft/intro.races#2 – Daniel Langr Jan 18 '19 at 09:49
  • @DanielLangr: Yes that is correct - there is no data race in that instance. But you would have to be careful to guard against one thread initialising the value. – Bathsheba Jan 18 '19 at 09:52
  • Sure, it can be also initialized prior to the existence of the threads. I just wanted to clarify, since OP does not specify whether the variable is read only or written as well. – Daniel Langr Jan 18 '19 at 09:54
1

It is safe if both threads just read that variable. If at least one updates it, then it's a data race -> undefined behavior.

Hidden mechanism are atomic operations. E.g., via making this variable of std::atomic<int> type in C++11.

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93