Подтвердить что ты не робот

Безопасен ли поток unique_ptr?

Безопасен ли поток unique_ptr? Невозможно ли для кода ниже печатать одинаковый номер дважды?

#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;
}
4b9b3361

Ответ 1

Нет, он не является потокобезопасным.

Оба потока могут потенциально move указатель на работу без явной синхронизации, поэтому для обоих потоков можно получить одно и то же значение или оба получить недопустимый указатель... это поведение undefined.

Если вы хотите сделать что-то подобное правильно, вам, вероятно, нужно будет использовать что-то вроде std::atomic_exchange, чтобы оба потока могли читать/изменять общий указатель рабочей области с помощью правильной семантики.

Ответ 2

unique_ptr является потокобезопасным при правильном использовании. Вы нарушили неписаное правило: никогда не пропускайте unique_ptr между потоками по ссылке.

Философия, лежащая в основе unique_ptr, заключается в том, что она имеет единственного (уникального) владельца во все времена. Из-за этого вы всегда можете безопасно передавать его между потоками без синхронизации - но вы должны передавать его по значению, а не по ссылке. Когда вы создаете псевдонимы для unique_ptr, вы теряете свойство уникальности, и все ставки отключены. К сожалению, С++ не может гарантировать уникальность, поэтому вы остаетесь с соглашением, согласно которому вы должны следовать религиозно. Не создавайте псевдонимы для unique_ptr!

Ответ 3

Согласно Msdn:

Следующие правила безопасности потока применяются ко всем классам Стандарта Библиотека С++ (кроме классов shared_ptr и iostream, как описано ниже).

Один объект является потокобезопасным для чтения из нескольких потоков. Для Например, учитывая объект A, безопасно читать A из потока 1 и из потока 2 одновременно.

Если один объект записывается одним потоком, то все считывает и запись в этот объект на том же или другом потоке должна быть защищенный. Например, если задан объект A, если поток 1 записывает A, то поток 2 должен быть запрещен для чтения или записи в A.

Безопасно читать и писать одному экземпляру типа, даже если другое поток читает или записывает в другой экземпляр того же типа. Например, если заданные объекты A и B того же типа, то безопасно, если A записывается в поток 1, а B читается в потоке 2.