При многопоточной работе исключена вероятность одновременнего доступа к ресурсам?
===================================================================================

 Заранее извиняюсь за большое количество текста. Я изучил довольно много информации на тему потоков. Разобрался с lock, мониторами, семафорами и мьютексами. Читал про `SynchronizationAttribute`, волатильность типов и класс `Interlocked`. Всё это мне более-менее понятно, но есть фундаментальный вопрос, который делает все остальные знания по теме бесполезными.   
  

Как я понял, когда я запускаю несколько потоков, то они не работают одновременно. На деле процессор сначала n секунд занимается одним потоком, потом n секунд - другим и т. д. Это называется переключение контекста. Но тогда выходит, что **одновременное обращение к переменной класса из разных потоков не возможно** ? Ведь на деле мы просто сначала n секунд будем работать с переменной из одного потока, потом n секунд - из другого и т.д. По этой же логике выходит, что **мы можем спокойно добавлять данные в список и удалять данные из того же списка из разных потоков**? Но тогда не очень понятно, зачем нужны классы из неймспейса `System.Collections.Concurrent`.   
  

Изучив информацию, я запомнил (но не понял), что **атомарные операции безопасны при работе в многопоточном коде** (это так?). Именно поэтому, например, инкрементация переменной с помощью `Interlocked.Add` безопасна и не приводит к проблемам. Текст получился несколько сумбурным, поэтому постараюсь подытожить:  

1. **Если никакой одновременности работы потоков нет, то как возможно одновременное изменение переменной из разных потоков?**  

2. **Почему атомарные операции всегда безопасны в отношении потоков?** 

 Ты не совсем понял проблему многопоточности. Да, чтение неизменяемого значения из множества потоков безопасно, но вот изменение - нет.  
  

На примере:  

Лежит в памяти значение `x = 1`. Пока его только читают, всё ок, но предположим, что это у нас какой-то счётчик и два потока хотят его увеличивать на 1.  
  

Первый поток считывает значение, кладёт его в стек, добавляет 1 и после записывает результат (2) обратно. Сам видишь, что тут отнюдь не одна операция, и между моментом считывания и записью проходит время. В это время второй поток может спокойно успеть считать пока ещё старое значение. Выходит, что оба потока возьмут 1, увеличать её на 1 и запишут в память, не важно в каком порядке. В результате вроде как оба потока отработало код, но значение в памяти увеличено только на 1. В этом и проблема.  
  

Списки, к примеру, внутри хранят тот же счётчик для количества элементов, поэтому одновременная запись может неправильно отработать. 

 Переключение контекста сохраняет все регистры процессора для потока и востанавливает для активного.  

Если у вас идет обращение к переменной через регистр (см. volatile), а не напрямую к адресу памяти, то сохранность актуального значения не гарантируется. Примерный сценарий:  

1. Первый поток поместил значение переменной в регистр (mov ax, [4C00h])  

2. Второй поток сохранил его в регистр (mov ax, [4C00h])  

3. Первый сделал какие-то операции над значением в регистре  

4. Второй сделал.  

5. Первый сохраняет значение по адресу памяти (mov [4C00h], ax)  

6. Второй.  
  

И вот какое значение сохранилось? Ведь каждый поток оперировал своими копиями регистров. И четкая последовательность вызова потоков тоже не гарантируется. 

[Михаил](http://toster.ru/user/makarychev13) имеется в виду что значение переменной может измениться при переходе от одной строки программы   
`x = 1;`  

к следующей строке   

```
Console.Error.WriteLine(x=" + x.ToString()); // undefined
```
  
  

даже если никакого кода меняющего `x`  

там нет - а произошло переключение конткста и другой поток записал свое значение в эту переменную 

> Как я понял, когда я запускаю несколько потоков, то они не работают одновременно. На деле процессор сначала n секунд занимается одним потоком, потом n секунд - другим и т. д. Это называется переключение контекста. 

  
  

Процессоров и ядер может быть несколько. Соотвествтвенно эти рассуждения только в случае одного процессора и одного ядра. Но и в случае одного ядра атомарность операций не гарантированна см комментарий [Meloman19](http://toster.ru/user/Meloman19)   
  

<https://habr.com/ru/company/intel/blog/243385/>  

[https://www.howtogeek.com/194756/cpu-basics-multip...](https://www.howtogeek.com/194756/cpu-basics-multiple-cpus-cores-and-hyper-threading-explained/)