Семафор - для чого корисний початковий підрахунок?


91

http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.aspx

Щоб створити семафор, мені потрібно вказати початковий та максимальний рахунок. MSDN стверджує, що початковий відлік -

Початкова кількість запитів на семафор, які можуть бути надані одночасно.

Хоча там зазначено, що максимальна кількість -

Максимальна кількість запитів на семафор, які можуть бути надані одночасно.

Я розумію, що максимальна кількість - це максимальна кількість потоків, які можуть одночасно отримувати доступ до ресурсу. Але яка користь від початкового підрахунку?

Якщо я створюю семафор з початковим підрахунком 0 і максимальним підрахунком 2, жоден з моїх потоків пулу потоків не зможе отримати доступ до ресурсу. Якщо я встановив початковий рахунок як 1 і максимальний як 2, тоді лише потік пулу потоків може отримати доступ до ресурсу. Тільки тоді, коли я встановлюю як початковий, так і максимальний рахунок як 2, 2 потоки можуть одночасно отримувати доступ до ресурсу. Отже, я справді збентежений значенням початкового підрахунку?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently

7
Як ви так і не прийняли відповіді SVGreg?
Джон

Відповіді:


79

Так, коли початкове число встановлено на 0 - усі потоки будуть чекати, поки ви збільшуєте властивість "CurrentCount". Ви можете зробити це за допомогою Release () або Release (Int32).

Випуск (...) - збільшить лічильник семафору

Зачекай (...) - зменшить його

Ви не можете збільшити лічильник (властивість "CurrentCount"), що перевищує максимальну кількість, яку ви встановили під час ініціалізації.

Наприклад:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()

1
Ваш код буде краще представлений у відповіді, а не як коментар.
ChrisF

15
LOL, мабуть, вже в п'ятий раз я доходжу до цієї самої відповіді, оскільки документація конструктора завжди бентежить, які значення встановлювати. Привітання
BlueStrat

71

Отже, я справді збентежений значенням початкового підрахунку?

Одним із важливих моментів, який тут може допомогти, є те, що Waitзменшує кількість семафорів і Releaseзбільшує його.

initialCount- кількість доступу до ресурсів, яка буде дозволена негайно. Або, іншими словами, саме стільки разів Waitможна викликати без блокування відразу після того, як семафор був інстанційований.

maximumCount- це найбільша кількість, яку може отримати семафор. Це кількість разів, Releaseяку можна викликати, не створюючи винятку, вважаючи, що initialCountрахунок дорівнює нулю. Якщо initialCountвстановлено таке саме значення, як maximumCountтоді виклик Releaseвідразу після створення семафору створить виняток.


20
Це так корисно! Я думав про Семафори назад, оскільки в InitiCount - це кількість початкових ЗАБЛОКОВАНИХ ресурсів, а не кількість ресурсів, доступних одразу. Дякую.
Філіп Тенн

5
@PhilipTenn, я згоден - документація щодо цього
незрозуміла

Я погодився, їм слід змінити цю назву змінної або оновити документи
IronHide

@Sandbox ви повинні прийняти цю відповідь IMO, оскільки це справді пояснює значення initialCountпараметра.
Міхал Турчин,

8

Скільки потоків ви хочете мати доступ до ресурсу одночасно? Встановіть початковий рахунок на це число. Якщо ця кількість ніколи не буде збільшуватися протягом усього терміну дії програми, встановіть для цього максимального числа також це число. Таким чином, якщо у вас є помилка програмування у випуску ресурсу, ваша програма вийде з ладу та повідомить вас про це.

(Є два конструктори: один, який приймає лише початкове значення, і той, який додатково приймає максимальну кількість. Використовуйте те, що підходить.)


1

Таким чином, коли поточний потік створює семафор, він може вимагати певні ресурси з самого початку.


Отже, ви маєте на увазі, коли я хочу, щоб два робочі потоки отримали доступ до ресурсу, мені слід змінити початковий рахунок?
Пісочниця

Ні. Це поточний потік, який вимагає підрахунку. Якщо ви не хочете, щоб поточний потік вимагав будь-який пропуск доступу 0 або використовував перевантаження одним параметром.
Ерно,

1

Якщо ви хочете, щоб жоден потік не мав доступу до вашого ресурсу протягом певного часу, ви передаєте початковий відлік як 0, а коли ви хочете надати доступ до всіх з них лише після створення семафора, ви передаєте значення початкового відліку, рівне максимальному підрахунку . Наприклад:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

Як цитується в Документації MSDN - "Інше використання ReleaseSemaphore використовується під час ініціалізації програми. Додаток може створити семафор з початковим рахунком нуль. Це встановлює стан семафора без позначення та блокує доступ усіх потоків до захищеного ресурсу. Коли програма закінчуючи свою ініціалізацію, він використовує ReleaseSemaphore, щоб збільшити кількість до максимального значення, щоб дозволити нормальний доступ до захищеного ресурсу. "


Вибачте, я дав вам приклад на C ++, хоча можу зняти сумнів.
Abhineet

0

Семафори можна використовувати для захисту пулу ресурсів . Ми використовуємо пули ресурсів для повторного використання речей, які дорого створювати - наприклад, підключення до бази даних.

Отже, початковий підрахунок відноситься до кількості доступних ресурсів у пулі на початку деякого процесу. Коли ви читаєте initialCountкод, ви повинні думати про те, скільки попередніх зусиль ви вкладаєте в створення цього пулу ресурсів.

Мене дуже бентежить значення первинного підрахунку?

Initial count = Upfront cost

Таким чином, залежно від профілю використання вашої програми, це значення може суттєво вплинути на продуктивність вашої програми. Це не просто якесь довільне число.

Вам слід добре подумати, що ви створюєте, наскільки дорого їх створювати і скільки вам потрібно відразу. Ви буквально мали б змогу побудувати графік оптимального значення для цього параметра і, напевно, повинні подумати про те, щоб зробити його настроюваним, щоб ви могли адаптувати продуктивність процесу до часу, коли він виконується.


-1

Як пояснює MSDN у розділі Зауваження:

Якщо InitialCount менше, ніж maximumCount, ефект такий самий, як якщо б поточний потік викликав WaitOne (maximumCount мінус InitialCount) разів. Якщо ви не хочете зарезервувати жодних записів для потоку, який створює семафор, використовуйте одне і те ж число для maximumCount і InitialCount.

Отже, якщо початковий відлік дорівнює 0, а макс. 2, це ніби WaitOne два рази викликався основним потоком, отже, ми досягли потужності (кількість семафорів зараз 0), і жоден потік не може ввійти в Semaphore. Подібним чином, якщо початковий рахунок дорівнює 1, а макс. 2, WaitOnce було викликано один раз, і лише один потік може ввійти до того, як ми знову досягнемо потужності тощо.

Якщо для початкового підрахунку використовується 0, ми завжди можемо викликати Release (2), щоб збільшити кількість семафорів до max, щоб дозволити максимальну кількість потоків отримувати ресурс.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.