Давайте разберемся с ними по одному:
someAsyncMethod {
serialQueue.async {
// When someAsyncMethod returns, this queue, behind the scenes,
// creates a Thread/NSThread object and approaches the
// semaphore and it is this thread object that decrements
// the semaphore counter.
// The next time someAsyncMethod returns, a new thread object
// is created behind the scenes (by the queue) and this thread
// object is made to wait until something (anything) signals
// it is done.
semaphore.wait()
// do work...
someMethod()
}
}
Сначала небольшая деталь, но async
не «создает» темы. GCD имеет пул рабочих потоков, и async
просто захватывает один из этих свободных рабочих потоков. (Вот почему GCD является производительным, поскольку он избегает создания / уничтожения потоков все время, что является дорогостоящим упражнением. Он использует aws в своем пуле рабочих потоков.)
Во второй раз, когда вы вызываете async
в той же последовательной очереди, вы можете получить тот же поток в следующий раз. Или вы можете получить другой рабочий поток из пула. У вас нет никаких гарантий в любом случае. Ваша единственная уверенность в том, что очередь является последовательной (потому что вы определили ее таковой).
Но, да, если семафор начинался со счетчика 1, то в первый раз он просто уменьшит счетчик и продолжит работу. , И, да, если этот семафор еще не был сигнализирован к тому моменту, когда вы добрались до этой секунды wait
, да, он будет ждать signal
.
Но идея использования этого ненулевого Семафор отправки в сочетании с последовательной очередью кажется весьма подозрительным. Обычно вы используете последовательные очереди для координации различных задач или, в редких случаях, используете семафоры, но почти никогда не используете оба одновременно. Как правило, наличие семафоров вообще касается, потому что почти всегда есть лучшие решения.
У вас тогда было:
func someMethod() {
// do work...
// This task may ultimately be on a different thread than
// where it started despite being in the same queue
// (since not every task is guaranteed to run on the same thread)
// but it doesn't matter, any object can signal the semaphore.
semaphore.signal()
}
Этот код, поскольку он был вызван изнутри serialQueue.async
предыдущего блока кода, он все равно будет работать в том же потоке, из которого вы вызывали someMethod
.
Так что, следовательно, этот код не совсем имеет смысла. Вы никогда не будете signal
из того же потока, который вызовет wait
в том же потоке. Весь смысл семафоров в том, что один поток может wait
для сигнала из другого потока.
Например, это может иметь смысл, если, например, someMethod
делает что-то эквивалентное to:
func someMethod() {
someOtherQueue.async {
// do work...
// Because this is dispatched to a different queue and we know is
// now running on a different thread, now the semaphore has some
// utility, because it only works if it’s a different thread than
// where we’ll later call `wait`...
semaphore.signal()
}
}
Теперь все это поднимает вопрос о назначении последовательной очереди вместе с этим семафором. Боюсь, что, пытаясь абстрагироваться от несвязанных деталей вашей кодовой базы, вы сделали это слишком абстрактным. Поэтому сложно посоветовать вам лучший шаблон без понимания более широкой проблемы, которую пытался решить этот код.
Но, без обид, почти наверняка будут намного лучшие подходы. Мы не можем просто не консультировать на основании предоставленной информации.
В заключение вы задали два вопроса:
- Отвечают ли семафоры на Speci c объектов / экземпляров потока?
Нет. Это для одного потока, чтобы сигнализировать другому, другому потоку. Но нет никаких других ограничений, кроме этого.
Создается ли новый объект / экземпляр потока каждый раз, когда someAsyncMethod возвращается и входит в очередь?
Как я уже говорил выше, замыкание отправляется в последовательную очередь с async
может оказаться в том же рабочем потоке или в другом рабочем потоке.
Но это не настоящая проблема здесь. Реальная проблема заключается в том, что вызовы wait
и signal
выполняются из отдельных потоков, а не в том, являются ли последующие вызовы wait
.