Я пробовал этот код, и он действительно умирает с недопустимой инструкцией. Поэтому я немного покопался и обнаружил, что он умирает в _dispatch_semaphore_dispose. Итак, давайте посмотрим, что это такое (ARMv7 здесь, потому что это легко понять!):
__dispatch_semaphore_dispose:
000040a0 b590 push {r4, r7, lr}
000040a2 4604 mov r4, r0
000040a4 af01 add r7, sp, #4
000040a6 e9d40108 ldrd r0, r1, [r4, #32]
000040aa 4288 cmp r0, r1
000040ac da00 bge.n 0x40b0
000040ae defe trap
...
Он умирает в 0x40ae, что является положительной инструкцией, поэтому он падает, если bge.n
не заставляет нас перепрыгивать через него.
Причина его неудачи в том, что r0
должно быть меньше r1
. r0
и r1
загружаются из памяти на r4 + 32
, который вернулся в стек, чтобы выяснить это. Я думаю, r4
- это aSemaphore
в примере кода, т.е. перешел в dispatch_semaphore_release
. + 32
означает, что он читает 32 байта в структуре, на которую указывает aSemaphore
(это указатель на структуру dispatch_semaphore_s
). В общем, что он делает, читает 4 байта из aSemaphore + 32
и помещает их в r0
, читает 4 байта из aSemaphore + 36
и помещает их в r1
.
Сравнение эффективно сравнивает значения aSemaphore + 32
и aSemaphore + 36
. Читая, что dispatch_semaphore_create
делает, я вижу, что он хранит значение, переданное как aSemaphore + 32
, так и aSemaphore + 36
. Я также обнаружил, что dispatch_semaphore_wait
и dispatch_semaphore_signal
касаются значения в aSemaphore + 32
, чтобы увеличивать и уменьшать его. Это означает, что причина его поломки заключается в том, что текущее значение семафора меньше значения, переданного в dispatch_semaphore_create
. Таким образом, вы не можете утилизировать семафор, если текущее значение меньше значения, с которым оно было создано.
Если вы прочитали здесь и поняли мои разговоры, то молодец! Надеюсь, это поможет!
UPDATE:
Вероятно, лучше посмотреть на источник (указанный JustSid) здесь - http://opensource.apple.com/source/libdispatch/libdispatch-187.7/src/semaphore.c - глядя на функцию _dispatch_semaphore_dispose
, которую мы видим:
if (dsema->dsema_value < dsema->dsema_orig) {
DISPATCH_CLIENT_CRASH("Semaphore/group object deallocated while in use");
}
Итак, да, вот так, вот почему он падает!