title: Deadlock caused by using NSUserDefaults' synchronize operation GCD queue
body: <h3>Context</h3>
  <p>We have an event tracking module which would report the collected events in batch when reporting condition triggered. Each event collected is tagged with a unique <code>event index</code>. In order to ensure the uniqueness, the work of the <code>event index</code> generation is put in a synchronization queue for this module would be called from other threads.</p>
  <h3>Code snippet</h3>
  <pre><code>class EventIndexManager {
  
  fileprivate static let sharedInstance = EventIndexManager()
  fileprivate var eventIndexQueue = DispatchQueue(label: &quot;com.johnkui.EventIndex.SyncQueue&quot;)
  fileprivate var curEventIndex: UInt64 = 0
  
  static func sharedManager() -&gt; EventIndexManager {
      return sharedInstance
  }
  
  func getEventIndex() -&gt; UInt64 {
      eventIndexQueue.sync {
          if self.curEventIndex != 0 {
              self.curEventIndex += 1
          } else {
              if let prevEventIndex = UserDefaults.standard.value(forKey: &quot;event_index&quot;) as? UInt64 {
                  self.curEventIndex = prevEventIndex + 1
              } else {
                  self.curEventIndex = 1
              }
          }
          
          let curEventIndex = self.curEventIndex
          eventIndexQueue.async {
              let eventIndex = self.curEventIndex &gt; curEventIndex ? self.curEventIndex : curEventIndex
              UserDefaults.standard.set(eventIndex, forKey: &quot;event_index&quot;)
              UserDefaults.standard.synchronize()
          }
      }
      
      return self.curEventIndex
  }
  }
  
  class EventTask: Taskable {
  var event: String
  var parameters: [String : Any]
  var eventIndex: UInt64
  
  init(event: String, parameters: [String : Any]) {
      self.event = event
      self.parameters = parameters
      self.eventIndex = EventIndexManager.sharedManager().getEventIndex()
      super.init()
  }
  }
  
  
  DispatchQueue.main.async(execute: { () -&gt; Void in
                  let task = EventTask(event: event, parameters: i18nParameters)
                  self.tasks.append(task)
              })
  </code></pre>
  <h3>Stack</h3>
  <p>Here is part of the calling stack</p>
  <p><a href="https://i.stack.imgur.com/W6sqb.png" rel="nofollow noreferrer">calling stack</a></p>
  <h3>Question</h3>
  <p>Why is the deadlock caused? What's wrong with my code snippet?</p>