dispatch_semaphore_wait does not wait on semaphore

萝らか妹 提交于 2019-12-22 09:49:39

问题


I have developed the following method, which checks the app's ability to communicate with the server. The method performs a simple query and knows that if it gets a result, the app should be connected (basic ping mechanism).

- (BOOL)isAppConnected
{
    __block BOOL isConnected = NO;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [[SFRestAPI sharedInstance] performSOQLQuery:@"SELECT id FROM Account LIMIT 1"
                                           failBlock:^(NSError *e) {
                                               isConnected = NO;
                                               NSLog(@"NOT CONNECTED %@", e);
                                               NSLog(@"fail block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]);

                                               dispatch_semaphore_signal(semaphore);

                                           } completeBlock:^(NSDictionary *dict) {
                                               isConnected = YES;
                                               NSLog(@"%@", dict);
                                               NSLog(@"complete block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]);

                                               dispatch_semaphore_signal(semaphore);
                                           }];

    // if the wait times-out we will receive a non-zero result and can assume no connection to SF
    //When using: DISPATCH_TIME_FOREVER the app hangs forever!!
    int waitResult = dispatch_semaphore_wait(semaphore, 30 * NSEC_PER_SEC); 
    NSLog(@"waitResult: %d", waitResult);

    return isConnected;
}

I am using the 'dispatch_semaphore_wait' as suggested in the Apple documentation

My goal is to wait on the response or a short timeout to figure out if we really have a valid connection.

With the code above, 'dispatch_semaphore_wait' never actually waits, i.e. execution does not stop at that line but it continues immediately (always returning 49 as the result to the dispatch_semaphore_wait call). That is unless I use DISPATCH_TIME_FOREVER in which case the app hangs forever...

At the moment I am calling this method from the main thread. I am aware that this is a bad idea, but I wanted to see this working as expected before refactoring.

What could be causing this behaviour? Thanks.


回答1:


The parameter for dispatch_semaphore_wait is not a delay, but the time when the semaphore should wake up. Yours will wake up 30 seconds after Midnight, Jan 1st. 1970 (or 2001, not sure). Use the dispatch_time function.




回答2:


- (BOOL)isAppConnected
{
    __block BOOL isConnected = NO;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    // Add this code...
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [[SFRestAPI sharedInstance] performSOQLQuery:@"SELECT id FROM Account LIMIT 1"
                                           failBlock:^(NSError *e) {
                                               isConnected = NO;
                                               NSLog(@"NOT CONNECTED %@", e);
                                               NSLog(@"fail block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]);

                                               dispatch_semaphore_signal(semaphore);

                                           } completeBlock:^(NSDictionary *dict) {
                                               isConnected = YES;
                                               NSLog(@"%@", dict);
                                               NSLog(@"complete block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]);

                                               dispatch_semaphore_signal(semaphore);
                                           }];
    });

    int waitResult = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"waitResult: %d", waitResult);

    return isConnected;
}



回答3:


First of all if your fail and complete block are invoked on the main thread then you are going to wait forever, or until the timeout you specify 'times out'

The reason is because the main thread starts waiting after you call dispatch_semaphore_wait. And then if your performSOQLQuery calls the blocks on the main thread nothing will happen until the time out 'times out'.

Now of coarse if you specify a time out of forever the semaphore will never signal or let go, which means your main thread will wait forever, for itself.

Change the waiting code to this: never make the main thread wait

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    int waitResult = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"waitResult: %d", waitResult);
});

And do not return a Bool as you are doing, since this is a lengthy operation, you want to use a block that has a result.

Also make sure that your performSOQLQuery() method is not on the main thread please.



来源:https://stackoverflow.com/questions/25528695/dispatch-semaphore-wait-does-not-wait-on-semaphore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!