Предположим, 2 потока параллельно обращаются к массиву из int. А в одном int хранится не одно значение, а 32 значения длиной в 1 бит. Поток обратившись, меняет там только 1 бит (обычный or или and), поэтому результат его действия (измененный int) зависит от того, какой был прочитанный. Синхронизация потоков нужна, т.к. если на этапе изменения int (который в регистре процессора), произойдет прерывание, то обработчик прерывания отправит значение регистра с помощью push в стек. Потом если произойдет переключение потоков, а 2-й поток перезапишет этот же int, и отправит в ОП, 1-й поток этого знать не будет (для него этот int находится в регистре, т.к. на момент прерывания он был там). Он будет восстановлен из стека и 1-й поток затрет изменения 2-го потока (пропадет перезаписанный 2-м потоком один бит).
Для изменения всего лишь одного бита вводить ВСЕГДА критические секции совсем неэффективно. Ведь реально — РЕДКИЙ СЛУЧАЙ, когда оба потока будут ломиться именно к одному значению int в массиве. Поэтому, зачем лишние блокировки? Я решил синхронизировать потоки так — сначала поток записывает в специальную переменную тот номер int из массива который он намерен "захватить", и только потом его меняет. 2-й поток будет приостановлен только в РЕДКИХ случаях когда оба потока одновременно захотят изменить это значение. Т.е. 2-й поток увидев что значение захвачено и используется, сбросит свою метку,(он же тоже уже пометил, что хочет захватывать это значение), и заснет на какое-то время. Потом снова пометит, что он хочет менять, снова проверит, не захвачено ли значение другим потоком и т.д. С таким подходом взаимной блокировки потоков быть не может, правда, теоретически возможно, что заснут оба потока со сброшенными метками, но здесь проблем нет — один из них проснется через константное время и продолжит работу. Я протестировал такой подход — ошибок пока не возникло ни одной, да и производительность возросла в 2 раза по сравнению с критическими секциями для всех обращений. И именно в этом месте крайне важна для меня производительность программы иначе бы я так не парился. Будет ли программа всегда работать правильно, и при всех изменениях архитектуры будущих компьютеров не будет ли сбоев?
Я не могу быть уверенным стопроцентно, т.к. не знаю толком, как работает аппаратура, память-проц-кэш-стек, как маппится в кэше процессора общая в ОП область памяти для разных потоков и т.д. Не запишет ли обработчик прерываний в стек чего лишнего, которое может быть потом затерто другим потоком? И могу ли я быть уверен, что после выполнения ВСЕГО "дизассемблерного" кода который я могу видеть, соответствующего моему common_value_for_thread1 = N; при любых состояниях системы и прерываниях, 2-й поток обратившись к common_value_for_thread1 действительно увидит там знчение N.