9 Replies
      Latest reply on Dec 16, 2019 2:06 AM by robson.tekever
      robson.tekever Level 1 Level 1 (0 points)

        Hello,

         

        After updating to Xcode 10 I started having an issue where the app freezes when waiting for a semaphore. I tried changing to dispatch groups but the same thing happens: it works normally with Xcode 10 and freezes with Xcode 11 (both stable and beta).

         

        The code is basically this:

         

        result = false

        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        dispatch_sync(dispatch_get_main_queue(), myBlock);

         

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        return result;

         

        Inside myBlock I display an AlertView that signals the semaphore when the uses presses either button.

        Simply changing to dispatch_async stops the freezing, but also breaks the functionality since I need the answer from the AlertView before returning.

        • Re: App freezes on Xcode11 when using dispatch group or semaphore
          eskimo Apple Staff Apple Staff (13,875 points)

          I’m confused by your code.  If you’re using a semaphore, why do you need to dispatch_sync?  The secondary thread will block on the semaphore until the main thread calls dispatch_semaphore_signal, so why does it need to call the main thread synchronously?

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

          ps DTS is closed 25…29 Nov in observance of the US Thanksgiving holiday.

            • Re: App freezes on Xcode11 when using dispatch group or semaphore
              robson.tekever Level 1 Level 1 (0 points)

              I was not the one who wrote the initial code, but from what I understand, the issue is that this method is originally called from another thread, several steps away:

               

              > dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{...

               

              And since what I need is to do is show an AlertView and wait for the user input, it needs to be done in the main thread, correct?

                • Re: App freezes on Xcode11 when using dispatch group or semaphore
                  eskimo Apple Staff Apple Staff (13,875 points)

                  And since what I need is to do is show an AlertView and wait for the user input, it needs to be done in the main thread, correct?

                  Right.  And you have to wait for the main thread to respond.  That all makes sense.  What doesn’t make sense is using two different ‘sync’ primitives to achieve the second goal.  Specifically:

                  • You call dispatch_sync, which runs the block on the main thread and doesn’t return until the block returns.

                  • You also use a semaphore to block the secondary thread until the alert completes.

                  If you have the latter, you don’t need the former.  You can dispatch_async to the main thread because you don’t need to wait until the block that posts the alert is finished.  Rather, you need to wait until the alert is done, and that’s what the semaphore does for you.


                  Notwithstanding the above, this technique is very concerning.  If any code on your main thread has a dependency on this secondary thread, or a resource held by the secondary thread, you run the risk of deadlock.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: App freezes on Xcode11 when using dispatch group or semaphore
                      robson.tekever Level 1 Level 1 (0 points)

                      If I only use dispatch_sync it does not achieve the result I want, the function returns before the block is executed.

                      I think this happens because this function is called from a thread that´s not the main one.

                       

                      Here´s the code below, when I put breakpoints, it executes in the following order:

                       

                      1. Block (presentViewController)

                      2. function returns with result = NO

                      3. Alert appears on screen.

                      4. User presses Yes/No

                      5. Executes AlertAction

                       

                      At this point, since the function has already returned, it does not achieve the expected result.

                       

                      __block BOOL result = NO;

                      //    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

                          dispatch_sync(dispatch_get_main_queue(), ^{

                              UIViewController *rootController = [IOSUtil visibleViewController];

                              UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[self getResourceText:caption]

                                                                                                       message:[self getResourceText:message]

                                                                                                preferredStyle:UIAlertControllerStyleAlert];

                            

                              [alertController addAction:[UIAlertAction actionWithTitle:cancelButtonText

                                                                                  style:UIAlertActionStyleDestructive

                                                                                handler:^(UIAlertAction *action) {

                                                                                    [LayoutIOS internalShowProgressControl];

                      //                                                              dispatch_semaphore_signal(semaphore);

                                                                                }]];

                            

                              [alertController addAction:[UIAlertAction actionWithTitle:okButtonText

                                                                                  style:UIAlertActionStyleDefault

                                                                                handler:^(UIAlertAction *action) {

                                                                                    result = YES;

                                                                                    [LayoutIOS internalShowProgressControl];

                      //                                                              dispatch_semaphore_signal(semaphore);

                                                                                }]];

                            

                              [LayoutIOS internalHideProgressControl];

                              [rootController presentViewController:alertController animated:YES completion:nil];

                          });

                        

                      //    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

                          return result;

                      • Re: App freezes on Xcode11 when using dispatch group or semaphore
                        robson.tekever Level 1 Level 1 (0 points)

                        Also, if I use dispatch_async and the semaphore, the app freezes the moment the user hits the yes/no button, it never reaches the AlertAction.

                          • Re: App freezes on Xcode11 when using dispatch group or semaphore
                            eskimo Apple Staff Apple Staff (13,875 points)

                            if I use dispatch_async and the semaphore, the app freezes the moment the user hits the yes/no button

                            I can’t run your code because it has dependencies on your various utility routines, so I rewrote it slightly to show this technique in a vanilla fashion:

                            - (void)viewDidLoad {
                                [super viewDidLoad];
                                // Do any additional setup after loading the view.
                                [NSThread detachNewThreadWithBlock:^{
                                    while (YES) {
                                        NSLog(@"will delay");
                                        [NSThread sleepForTimeInterval:5.0];
                                        NSLog(@"did delay");
                                        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
                                        dispatch_async(dispatch_get_main_queue(), ^{
                                            NSLog(@"will show alert");
                                            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Hello Cruel World!"
                                                message:nil
                                                preferredStyle:UIAlertControllerStyleAlert
                                            ];
                            
                                            [alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
                                                style:UIAlertActionStyleDestructive
                                                handler:^(UIAlertAction * action) {
                                                    NSLog(@"alert cancel");
                                                    dispatch_semaphore_signal(semaphore);
                                                }
                                            ]];
                            
                                            [alert addAction:[UIAlertAction actionWithTitle:@"OK"
                                                style:UIAlertActionStyleDefault
                                                handler:^(UIAlertAction * action) {
                                                    NSLog(@"alert OK");
                                                    dispatch_semaphore_signal(semaphore);
                                                }
                                            ]];
                            
                                            [self presentViewController:alert animated:YES completion:nil];
                                            NSLog(@"did show alert");
                                        });
                                        NSLog(@"will wait for alert");
                                        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                                        NSLog(@"did wait for alert");
                                    }
                                }];
                            }

                            If I add this code to a new app created from the iOS > Single View App template, it does what I’d expect, that is, the secondary thread runs and, every 5 seconds, it posts an alert and waits for the response.

                            This is using Xcode 11.3 on the iOS 13.3 simulator.

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: App freezes on Xcode11 when using dispatch group or semaphore
                                robson.tekever Level 1 Level 1 (0 points)

                                I tried your code and the same thing happens, the function returns before the alert is shown, and the alert is displayed after that. When the user presses either button, the application freezes.

                                 

                                Might be due to the fact that this function is called from inside another dispatch:

                                 

                                > dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{...

                                 

                                Edit: after trying on a new app and using the above additional dispatch async to wrap it I confirmed that it does work on a void function, but when the function returns a value, it always happens before the block is executed.

                                  • Re: App freezes on Xcode11 when using dispatch group or semaphore
                                    eskimo Apple Staff Apple Staff (13,875 points)

                                    voice function

                                    Huh?  Perhaps you can tweak my example to show the problem you’re having?

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"

                                      • Re: App freezes on Xcode11 when using dispatch group or semaphore
                                        robson.tekever Level 1 Level 1 (0 points)

                                        Sorry, I meant to say "void" but the corrector changed it to "voice".

                                         

                                        I ran your code on a new app trying to create a similar solution to what I have in mine: making the function return a bool value and wrapping the function call in a dyspatch_async like the one in my previous comment. And it does work as expected, which means there is something else in my app that is causing this. Maybe it´s the deadlock situation you described above. Thank you for helping me clear this out, I will report back when I find the problem.