Is unique_ptr thread safe?

20,282

Solution 1

No, it isn't thread-safe.

Both threads can potentially move the work pointer with no explicit synchronization, so it's possible for both threads to get the same value, or both to get some invalid pointer ... it's undefined behaviour.

If you want to do something like this correctly, you probably need to use something like std::atomic_exchange so both threads can read/modify the shared work pointer with the right semantics.

Solution 2

unique_ptr is thread safe when used correctly. You broke the unwritten rule: Thou shalt never pass unique_ptr between threads by reference.

The philosophy behind unique_ptr is that it has a single (unique) owner at all times. Because of that, you can always pass it safely between threads without synchronization -- but you have to pass it by value, not by reference. Once you create aliases to a unique_ptr, you lose the uniqueness property and all bets are off. Unfortunately C++ can't guarantee uniqueness, so you are left with a convention that you have to follow religiously. Don't create aliases to a unique_ptr!

Solution 3

According to Msdn:

The following thread safety rules apply to all classes in the Standard C++ Library (except shared_ptr and iostream classes, as described below).

A single object is thread safe for reading from multiple threads. For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously.

If a single object is being written to by one thread, then all reads and writes to that object on the same or other threads must be protected. For example, given an object A, if thread 1 is writing to A, then thread 2 must be prevented from reading from or writing to A.

It is safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given objects A and B of the same type, it is safe if A is being written in thread 1 and B is being read in thread 2.

Share:
20,282
Valentin Milea
Author by

Valentin Milea

Updated on July 15, 2020

Comments

  • Valentin Milea
    Valentin Milea almost 4 years

    Is unique_ptr thread safe? Is it impossible for the code below to print same number twice?

    #include <memory>
    #include <string>
    #include <thread>
    #include <cstdio>
    
    using namespace std;
    
    int main()
    {
        unique_ptr<int> work;
    
        thread t1([&] {
            while (true) {
                const unique_ptr<int> localWork = move(work);
                if (localWork)
                    printf("thread1: %d\n", *localWork);
                this_thread::yield();
            }
        });
    
        thread t2([&] {
            while (true) {
                const unique_ptr<int> localWork = move(work);
                if (localWork)
                    printf("thread2: %d\n", *localWork);
                this_thread::yield();
            }
        });
    
        for (int i = 0; ; i++) {
            work.reset(new int(i));
    
            while (work)
                this_thread::yield();
        }
    
        return 0;
    }
    
  • Nicol Bolas
    Nicol Bolas almost 12 years
    "Excitingly, when and if this happens, it will also result in double-freeing of the integer." It might. It might not. It might result in not freeing the integer at all. It might result in both of the moved versions having half of the pointer's value. It could do all kinds of things.
  • Ghita
    Ghita almost 12 years
    Interesting observation. I try to think when it makes sense to transfer unique_ptr by reference then. I mean when there is the case that you don't want to pass ownership.
  • Useless
    Useless almost 12 years
    True, I was making some assumptions about the architecture which aren't really warranted.
  • Valentin Milea
    Valentin Milea almost 12 years
    If 'passing between threads' means starting a new thread with unique_ptr argument, then you could replace unique_ptr with just about any type and still call it thread safe. Anything is thread safe when used correctly :)
  • NoSenseEtAl
    NoSenseEtAl over 11 years
    u sure about this? my inner paranoid programmer tells me that if you pass the up between threads it is UB because you dont ensure seq_cst, aka if what up points to is modified by thread 1 and then up is passed to thread 2 then thread 2 might see stale values of pointed to stuff.
  • Bartosz Milewski
    Bartosz Milewski about 11 years
    @ValentinMilea : It's not safe to pass an arbitrary pointer to a thread. You were probably thinking about passing values which have copy semantics -- these are indeed safe.
  • Valentin Milea
    Valentin Milea about 11 years
    @BartoszMilewski : I meant there is nothing special about unique_ptr. You can safely pass arbitrary arguments when creating a thread, including plain pointers as long as the pointed data stays consistent: p = new A; thread t([](A *p) { ... }, p); p = nullptr;
  • SnakE
    SnakE over 7 years
    -1. When people ask about thread safety they actually ask whether accessing one instance of an object from multiple threads at the same time is safe. In this sense unique_ptr is no safer than T*.
  • fabian
    fabian over 2 years
    "Don't create aliases to a unique_ptr!" According to this statement the move assignment operator of std::unique_ptr is using bad practices. So as a corrolary transferring ownership from one std::unique_ptr to another is bad practice just to follow this overly broad rule...
  • Paul Sanders
    Paul Sanders almost 2 years
    This answer makes no sense. You can't pass a unique_ptr by value.
  • Paul Sanders
    Paul Sanders almost 2 years
    At last, a sensible answer.