2011-07-06 9 views
3

documentation for dispatch_semaphore_waitには、「信号のFIFO順で待機する」と記載されています。しかし、この例のようには見えません - 誰かが説明できますか?dispatch_semaphore_wait FIFOはありませんか?

例:

#include <dispatch/dispatch.h> 
#include <stdio.h> 

dispatch_queue_t q1, q2; 
dispatch_semaphore_t sem; 
int g_call; 

void do_work(void) 
{ 
    int s = 0; 
    int i; 
    for (i = 0; i < 100000000; ++i) 
     ++s; 
} 

void f1(int call) 
{ 
__block int waited = 0; 
    dispatch_async(q1, ^{ 
     while (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC/1000))) 
      waited = 1; 
     printf("1:%d %s\n", call, waited ? "waited" : ""); 
     do_work(); 
     dispatch_semaphore_signal(sem); 
    }); 
} 

void f2(int call) 
{ 
    __block int waited = 0; 
    dispatch_async(q2, ^{ 
     while (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC/1000))) 
      waited = 1; 
     printf("\t\t2:%d %s\n", call, waited ? "waited" : ""); 
     do_work(); 
     dispatch_semaphore_signal(sem); 
    }); 
} 

int main(int argc, char **argv) 
{ 
    q1 = dispatch_queue_create(NULL, NULL); 
    q2 = dispatch_queue_create(NULL, NULL); 
    sem = dispatch_semaphore_create(1); 
    g_call = 0; 

    dispatch_queue_t q_global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q_global); 
    const uint64_t DELAY = 10; 
    dispatch_source_set_event_handler(timer, ^{ 
     f1(g_call); 
     f2(g_call); 
     ++g_call; 
     dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, DELAY), 0, 0); 
    }); 
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, DELAY), 0, 0); 
    dispatch_resume(timer); 

    sleep(3); 
} 

期待出力:

1:0 
     2:0 
1:1 
     2:1 
1:2 
     2:2 
... 

実際の出力(一例):

1:0 
1:1 
... 
1:14 
     2:0 waited 
     2:1 
     ... 

編集:もし実際の出力ではなく、あるシリアルキューのq1とq2はグローバルキューに設定されます。

1:0 
     2:8 waited 
1:3 waited 
1:4 waited 
     2:3 waited 
1:6 waited 
1:9 waited 
     2:9 waited 
     2:21 
1:28 waited 

(時にはそれが完璧に動作しますが、時にはそれがこのような奇妙だ。)

答えて

3

dispatch_queue_createは、シリアルキューを作成し、シリアルキューはpthreadのスレッドを作成します(私はそうわからないんだけど... )。

そして、dispatch_semaphore_waitはパフォーマンスのためにセマフォを取得するためにスピンロックを使用します。つまり、pthread_mutex_lockのようなコンテキスト切り替えポイントではありません。コンテキストを頻繁に切り替えることはありません。

グローバルキューを使用すると、コードは期待どおりに出力されます(しかし、まったく同じではありません)。グローバルキューはpthreadワークキューを使用するためです。切り替えコンテキストの動作は、スレッドスレッドの動作とは異なります。

q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
q2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

EDITED:

グローバルキューを順次所定のタスクを実行するが、これらのタスクが同時に実行され、出力順は、コンテキストスイッチにより変化してもよいです。さらに、コードのタイマーは10ナノ秒ごとに起動します。同時に実行するタスクが多すぎます。

別の簡単な例として、私の8core MacBook Proの上で

dispatch_queue_t queue = 
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_apply(10, queue, ^(size_t index) { 
    printf("%zu\n", index); 
}); 

:助けexplanation--ため

4 
2 
0 
6 
3 
1 
5 
8 
9 
7 
+0

感謝。しかし、q1とq2をグローバルキューにすると動作することがありますが、時には出力が完全に順不同です。私の編集を参照してください。なぜこれが起こっているのか? (もしそれがセマフォーか、並べ替えをやっているグローバルな待ち行列であるかわかりません) – jlstrecker

+0

私の答えが更新されました。 –

関連する問題