Сомнительная потребность в мьютексе с общими ресурсами

В настоящее время у меня есть механизм, в котором 2 потока читают/записывают одни и те же данные; хотя и не одновременно; и не используйте никаких механизмов синхронизации.

Возможно, самым простым примером будет (псевдокод)

x = 5;
startThread(changeX).join()
assert(x != 5)

таким образом, мы можем быть уверены, что рассматриваемый поток обработал x до того, как он будет прочитан стартовым потоком.

Является ли это неопределенным поведением (поскольку x может быть оптимизирован) или оно безопасно?

Мой опыт работы с С++ и мои исследования до сих пор говорят о небезопасности, но я не вижу ничего определенного.

Реальный вопрос в том, есть ли шансы на столкновение двух потоков? если есть шанс, я бы сказал, что вам нужно синхронизировать

Prix 30.05.2019 14:46

@Prix, давайте согласимся, что нет .... это все еще безопасно (например, может ли компилятор что-то оптимизировать для меня)?

UKMonkey 30.05.2019 14:47

Существует также вероятность того, что вы прочитаете его, прежде чем писать в него, нежелательно ли такое поведение? если да, то я бы сказал синхронизация, если ее нет, то я не вижу ничего, что могло бы вас удержать. Компилятор не будет создавать блокировки за вас. если компилятор считает код бесполезным, он может его оптимизировать. Например, если вы напишете var test = true; и скомпилируете его при выпуске.

Prix 30.05.2019 14:48

Использование вами слова «по-видимому» вызовет некоторые сомнения в том, что они никогда не сталкивались.

user47589 30.05.2019 14:49

@UKMonkey То, как этот код написан, родительский поток блоки в ожидании завершения дочернего потока. Часть субoptimal заключается в том, что создается новый поток вместо выбора бездействующего потока из пула потоков. Вы можете использовать, например, Task.Run(()=>changeX(...)).Wait(); для использования потока из пула или await Task.Run.... для асинхронного ожидания.

Panagiotis Kanavos 30.05.2019 14:50

Для меня ключевое слово «кажется». Мы можем вечно тестировать многопоточный код, не видя проблем, а потом они возникают, как только наше приложение оказывается в какой-то другой среде. Скорее всего, мы просто не будем знать, когда это произойдет, что позволит дольше вызывать проблемы. Потом кто-то что-то сообщает, но мы не можем это повторить. Затем мы повторяем это, но никто не может понять, в чем проблема.

Scott Hannen 30.05.2019 14:52

@PanagiotisKanavos прав, но это не говорит о том, безопасно это или нет.

UKMonkey 30.05.2019 14:52

Слишком верно - мое сомнение в коде, на который я смотрю, не должно влиять на основы вопроса ... позвольте мне настроить.

UKMonkey 30.05.2019 14:53

@UKMonkey это так - другой поток работает нет, когда вы звоните assert(x != 5). У кода другая проблема — что делает changeX? Ints - это типы значений, поэтому changeX не может изменить X, если он не передан по ссылке.

Panagiotis Kanavos 30.05.2019 14:54

@UKMonkey, что такое x? Переменная? Поле? Имущество? Зачем использовать такую ​​тему вместо, например, x = await Task.Run(()=>someHeavyWork()?

Panagiotis Kanavos 30.05.2019 14:55

Переменная-член (класс) @PanagiotisKanavos - в С++ компилятор мог бы разумно взглянуть на это; и не выполнить утверждение, потому что x не мог быть изменен данным потоком, и вокруг x нет синхронизации, чтобы сообщить компилятору, что он может измениться. Я просто недостаточно хорошо знаю спецификацию С#, чтобы увидеть, можно ли применить те же оптимизации

UKMonkey 30.05.2019 14:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При условии, что вы пишете псевдокод, я могу сказать вам следующее:

1 - Эмпирическое правило: всякий раз, когда 2 потока выполняют запись/чтение одной и той же переменной, вам необходимо учитывать использование потокобезопасных структур, и вы всегда должны использовать какую-то синхронизацию между потоками.

2 - Хотя в вашем случае вы работаете с атомарными переменными, у вас не будет проблем при выполнении чтения/записи, но здесь у вас может быть состояние гонки, и у вас могут быть случайные выходные данные в зависимости от того, как Windows решает обрабатывать потоки .

Принимая во внимание обе вещи, я настоятельно рекомендую вам использовать некоторую синхронизацию, чтобы не получать случайные результаты в зависимости от того, как Windows решает обрабатывать ваши потоки. Ваше чутье в С++ говорит вам что-то, потому что здесь что-то происходит

Другие вопросы по теме