2011-07-06 226 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创建一个串行队列,然后串行队列创建并行线程的线程(我不那么肯定...... )。

dispatch_semaphore_wait使用自旋锁来获取性能的信号量。这意味着它不是作为pthread_mutex_lock的上下文切换点。它不经常切换上下文。

如果您使用全局队列,您的代码将按照您的预期输出(但它不完全相同)。因为全局队列使用pthread工作队列。切换上下文的行为不同于pthread线程的行为。

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

EDITED:

全局队列顺序执行给定的任务,但这些任务正在执行同时地,输出顺序可以通过上下文切换而变化。而且,你的代码的计时器每10纳秒触发一次,太多的任务正在并发执行。

另一个简单的例子,

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

在我8core的MacBook Pro:

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

感谢您的帮助explanation--。但是如果我让q1和q2成为全局队列,有时候它会起作用,但有时输出却完全失序。查看我的编辑。任何想法为什么发生这种情况? (我不确定这是信号量还是全局队列正在进行重新排序。) – jlstrecker

+0

更新了我的答案。 –

相关问题