109: (Default)
[personal profile] 109
а вот это, наоборот, явно можно сделать проще, даже когда брадобреев много.

// вначале семафор закрыт
newCustomer = new AutoResetEvent(false); 

// customer reception thread[s]
lock (queue) {
  if (queue.Size == maxSize)
    throw "нет мест";
  queue.Enqueue(сustomer);
  newCustomer.Set(); // open semaphore
}

// each barber's thread
while (true) {
  newCustomer.WaitOne(); // let one barber through and close
  lock (queue) {
    if (queue.IsEmpty) 
      continue;
    customer = queue.Dequeue();
  }
  Shave(customer);
}
собственно, этот же код решает и проблему продюсеров-консъюмеров, вместо того, что там написано (на буфер памяти нет, а спящие треды копить память есть, да?)

(no subject)

Date: 2009-11-01 10:07 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
А что случится если кастомер ресепшен тред обработает двух кастомеров пока барберы всё ещё спят? AutoResetEvent.Set вроде не блокируется и вообще не гарантирует ничего? И, типа, через несколько суток работы очередь переполняется, все в ахуе, никто ничего не понимает, етс.

(no subject)

Date: 2009-11-02 01:22 am (UTC)
From: [identity profile] 109.livejournal.com
а, точно. WaitOne нужно с таймаутом пускать.

(no subject)

Date: 2009-11-02 09:28 am (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
С каким именно?

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

Вообще его наверное можно исправить заменив этот эвент на семафор. Типа, на каждого поставленного в очередь кустомера ресепшен тред делает +1, а барберы лочатся в попытках сделать -1.


А так, по-моему, довольно явственно проявилось, что использование хитроумных локов для синхронизации самоподдерживается через Dunning–Kruger effect =)

(no subject)

Date: 2009-11-02 11:06 pm (UTC)
From: [identity profile] 109.livejournal.com
> С каким именно?

с экспоненциальным бэкоффом. хотя ты прав в том смысле, что тогда получится не особо проще того, что в википедии написано.

> По любому же получится, что в течение какого-то времени чувак тусуется в очереди хотя есть свободные барберы.

это ты про когда два сразу пришли?

> Вообще его наверное можно исправить заменив этот эвент на семафор. Типа, на каждого поставленного в очередь кустомера ресепшен тред делает +1, а барберы лочатся в попытках сделать -1.

напиши, если не трудно, в явном виде?

(no subject)

Date: 2009-11-03 01:06 am (UTC)
From: [identity profile] 109.livejournal.com
я вспомнил, что эту задачу уже раньше решал. ну или очень похожую.

AutoResetEvent signal = new AutoResetEvent(false);
object queueLock = new object();
Queue queue = new Queue();
Queue next = new Queue();

public void Next()
{
	next.Enqueue(queue.Dequeue());
	signal.Set();
}

public void AcceptCustomer(T customer)
{
	lock (queueLock)
	{
		if (queue.Count > 9000)
			throw new Exception("нет мест");
		queue.Enqueue(customer);
		if (next.Count == 0) 
			Next();
	}
}

public void BarbersThread()
{
	while (true)
	{
		signal.WaitOne(); // let one barber through and close
		T customer;
		lock (queueLock)
		{
			customer = next.Dequeue();
			if (queue.Count > 0)
				Next();
		}
		Shave(customer);
	}
}


any feedback will be greatly appreciated.

(no subject)

Date: 2009-11-03 08:59 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
Нифига не понял, что и зачем делает эта версия и почему в ней не возникнет этой же проблемы: "AutoResetEvent.Set: Sets the state of the event to signaled, which allows at most one waiting thread to proceed", соответственно если вызвать его даже не два, а много раз подряд, скажем, в три раза больше раз, чем у нас есть брадобреев, то часть сигналов проебётся -- не разбудит ни одного брадобрея. Поскольку брадобреи бреют не более чем одного кастомера на сигнал, будут накапливаться необслуженные кастомеры.

С этим можно бороться, например брадобреи могут делать так: while (true): lock, get customer, and signal.WaitOne() only if no customers. Не забыв отпустить лок конечно же =) Поскольку тред на ресепшене делает Set после того, как записывает очередного кастомера, всё сработает правильно (и этот Сет вообще говоря тоже нехило бы вынести из-под лока). Из недостатков -- ну, каждый брадобрей, ухвативший более одного кастомера с одного WaitOne, скорее всего стырил его у какого-то другого брадобрея, который по сигналу проснётся, залочит очередь и ничего там не обнаружит, это неэффективно.

Я предлагал другой способ: вместо AutoResetEvent используется Semaphore, ресепшен вызывает Release, барберы -- WaitOne. В отличие от мьютекса семафор не требует, чтобы релизил тот же тред, что лочил. В отличие от AutoResetEvent семафор не проёбывает число релизов. И вроде как довольно очевидно, что если у семафора установить тот же лимит, что и у очереди, то он не переполнится (а если и переполнится, то это не пройдёт бесследно, что ДИКО хорошо). Потому что ресепшен вначале пушит в очередь, потом в семафор, а барберы достают в обратном порядке.


Разумеется, ни в чём вышесказанном я не уверен и только массивные полевые испытания под жуткой нагрузкой могут немного этой уверенности прибавить.

PS: кстати, что за фигня с Reference Source (http://referencesource.microsoft.com/), не в курсе? Что-то оно похоже превратилось в зомби сразу после открытия (в смысле что за блогом, форумом и документацией никто не следит ваще), но вроде что-то иногда выкладывают (вот, под семёрку что-то выложили). И заставить его работать мне не удалось.

(no subject)

Date: 2009-11-03 10:38 pm (UTC)
From: [identity profile] 109.livejournal.com
Нифига не понял, что и зачем делает эта версия и почему в ней не возникнет этой же проблемы: "AutoResetEvent.Set: Sets the state of the event to signaled, which allows at most one waiting thread to proceed", соответственно если вызвать его даже не два, а много раз подряд, скажем, в три раза больше раз, чем у нас есть брадобреев, то часть сигналов проебётся -- не разбудит ни одного брадобрея. Поскольку брадобреи бреют не более чем одного кастомера на сигнал, будут накапливаться необслуженные кастомеры.

мля-а, ну кода же три строчки, что тут непонятного? я не верю, что ты посмотрел и не понял; я о тебе очень высокого мнения. давай ты посмотришь ещё раз, прежде чем я начну объяснять.

(no subject)

Date: 2009-11-03 10:50 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
А!

Меня вот что запутало: я же правильно понимаю, что в очереди next никогда не должно быть больше одного кастомера, то есть её можно смело превратить в `Customer next;` и вместо `if (next.count > 0)` писать `if (next != null)`, ну а вместо `next.Dequeue` -- `customer = next; next = null`?

Тогда да, кажется тоже работает.

(no subject)

Date: 2009-11-03 10:54 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
или даже вообще, volatile bool barberPending. Чтобы как бы совсем понятно было.

(no subject)

Date: 2009-11-03 11:03 pm (UTC)
From: [identity profile] 109.livejournal.com
а это будет уже совсем непонятно. pending-то кастомер, а не барбер.

и куда его совать-то, этот volatile? вместо локов не получится, локи всё равно нужны. а тогда лишний point of synchronization. но всё равно не понимаю, куда.

(no subject)

Date: 2009-11-03 11:17 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
Эм, он volatile для того, чтобы компилятор не соптимизил доступ к нему.

В принципе может быть это и не нужно в данном конкретном случае -- lock сам по себе вроде бы является read-write barrier (но вот насчёт read не уверен, кстати!), однако над такими вещами лучше не задумываться излишне, по-моему.

Не, это barberAwakeningPending имелось в виду!

(no subject)

Date: 2009-11-04 02:05 am (UTC)
From: [identity profile] 109.livejournal.com
я знаю, зачем нужен volatile, я не понимаю, куда его тут совать. ну обнаружили мы, что нету барберов pending, дальше что? спинлочить? не думаю, что ты это имел в виду. код можешь написать?

и да, lock - это всегда both read and write barrier, (иначе бы не работало ничего).

(no subject)

Date: 2009-11-03 11:00 pm (UTC)
From: [identity profile] 109.livejournal.com
можно и так, но с двумя очередями очевиднее, что происходит (в явном виде употребляются слова enqueue и dequeue), и more generic - мало ли, в следующий раз по два кастомера брать надо будет.

Profile

109: (Default)
109

March 2019

S M T W T F S
     12
3456789
101112131415 16
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags