Page 72 - 4989
P. 72

імовірно завершиться помилкою. У табл. 7.1 показано ситуацію, в
            якій два потоки одночасно виконують фрагмент коду на зразок
                  N+=delta;
                  де  N  –  це  глобальна  змінна.  Рядки  таблиці  представляють
            інтервали часу, що слідують один за одним.

                      Таблиця 7.1 – Приклад конфлікту доступу до глобальної
                                                     змінної

                             Потік 1                                        Потік 2
            зчитування          значення         N     в  зчитування          значення         N      в

            регістр процесора 1                            регістр процесора 2
            зміна       значення        в     регістрі  зміна         значення         в     регістрі

            процесора 1 (додавання delta)                  процесора 2 (додавання delta)
            запис  значення  в  оперативну  очікування доступу до пам’яті
            пам’ять
                                                           запис  значення  в  оперативну

                                                           пам’ять

                  Одночасний запис в оперативну пам’ять двох різних значень
            фізично  неможливий,  тому  менеджер  пам’яті  призупинить

            виконання одного із потоків, поки другий потік не виконає запис,
            і  відновить  виконання  після  завершення  запису.  Однак
            результуюче  значення  змінної  N  після  виконання  цього  коду
            збільшиться  на  delta,  а  не  на  delta*2  (як,  очевидно,  було

            задумано),  бо  другий  потік  буде  оновлювати  старе  значення  N,
            отримане з пам’яті одночасно з першим потоком. Слід зауважити,
            що  подібна  ситуація  може  статися  навіть  тоді,  коли  в  системі

            присутній  всього  один  логічний  процесор,  якщо  потік  2  буде
            витіснений  потоком  1  безпосередньо  перед  записом  значення  в
            оперативну пам’ять.
                  Для  уникнення  такої  ситуації  необхідно,  щоб  виконання

            рядка  N+=delta  для  деякого  потоку  було  відкладено,  поки  його
            виконує  інший  потік.  Найпростіший  спосіб  такого  блокування
            забезпечує           об’єкт         синхронізації            «критична           секція»

            (CRITICAL_SECTION).                     Критичну             секцію          необхідно
            ініціалізувати  функцією  InitializeCriticalSection,  після  чого
            деякий  фрагмент  коду  можна  захистити  за  допомогою  функцій

            EnterCriticalSection та LeaveCriticalSection:


                                                           72
   67   68   69   70   71   72   73   74   75   76   77