Семафор (информатика)

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Семафо́р (англ. semaphore) — объект, ограничивающий количество потоков, которые могут войти в заданный участок кода. Определение введено Эдсгером Дейкстрой. Семафоры используются для синхронизации и защиты передачи данных через разделяемую память, а также для синхронизации работы процессов и потоков.

Определение семафора[править | править вики-текст]

Семафор — это объект, над которым можно выполнить три операции.

Инициализация семафора (задать начальное значение счётчика):

init(n):
    счётчик := n

Захват семафора (ждать пока счётчик станет больше 0, после этого уменьшить счётчик на единицу):

enter():
    счётчик := счётчик - 1

Освобождение семафора (увеличить счётчик на единицу):

leave():
    счётчик := счётчик + 1

Предположим, что есть такой участок кода:

semaphore.init(5);
// .....
// .....
void DoSomething()
{
    semaphore.enter();
    // .......
    semaphore.leave();
}

Тогда не более пяти потоков могут одновременно выполнять функцию DoSomething().

В более сложных семафорах может использоваться очередь; при этом потоки, ожидающие освобождения семафора, будут проходить через семафор именно в том порядке, в котором они вызывали enter().

Применение семафоров[править | править вики-текст]

Некоторые из проблем, которые могут решать семафоры:

  • запрет одновременного выполнения заданных участков кода (критические секции);
  • поочерёдный доступ к критическому ресурсу (важному ресурсу, для которого невозможен (или нежелателен) одновременный доступ);
  • синхронизация процессов и потоков (например, можно инициировать обработку события отпусканием семафора).

Следующий пример показывает, как наладить поочерёдный доступ к консоли.

semaphore.init(1);

// Поток 1:
semaphore.enter();
cout << "Состояние массива: ";
for (int i=0; i<n; i++)
    cout << a[i] << ' ';
cout << '\n';
semaphore.leave();

// Поток 2:
semaphore.enter();
cout << "Нажато Esc.\n";
semaphore.leave();

Этот код поможет предотвратить появление вывода наподобие

Состояние массива: 1 2 3 Нажато Esc.
4 5 6

Проблемы семафоров[править | править вики-текст]

Во-первых, можно написать программу с «утечкой семафора», вызвав enter() и забыв вызвать leave(). Реже встречаются ошибки, когда дважды вызывается leave().

Во-вторых, семафоры чреваты взаимной блокировкой потоков. В частности, опасен такой код:

// Поток 1:
semaphore1.enter();
semaphore2.enter();
// ...
semaphore2.leave();
semaphore1.leave();

// Поток 2:
semaphore2.enter();
semaphore1.enter();
// ...
semaphore1.leave();
semaphore2.leave();

См. также[править | править вики-текст]

Литература[править | править вики-текст]

  • Грегори Р. Эндрюс. Основы многопоточного, параллельного и распределённого программирования. — Вильямс, 2003.

Ссылки[править | править вики-текст]