是不是dispatch_semaphore_wait FIFO?

时间:2011-07-06 18:30:58

标签: grand-central-dispatch libdispatch

documentation for 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

(有时候效果很好,但有时这很奇怪。)

1 个答案:

答案 0 :(得分:3)

dispatch_queue_create创建一个串行队列,然后串行队列创建一个pthread线程(我不太确定......)。

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);

<强>编辑:

全局队列按顺序执行给定任务,但这些任务同时执行,输出顺序可能因上下文切换而异。此外,代码的计时器每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);
});

在我的8核MacBook Pro上:

4
2
0
6
3
1
5
8
9
7