2015-07-03 64 views
0

我正在使用异步排队进程,我需要更新计数器以跟踪进度。Swift:串行队列中的线程安全计数器

这是一个例子贴近我的代码(我不是张贴我的实际代码原因它与回调特定的图书馆,它是不是真的点):

var downloadGroup = dispatch_group_create() 

counter = Float(0) 
total = Float(urls.count) 

var myData = [MyData]() 

for url in urls { 
    dispatch_group_enter() 
    process.doAsync(url) { 
     // Success callback called on main thread 

     data in 

     myData.append(data) // Append data from url to an array 

     counter++ // Here counter should increment for each completed task, but it doesn't update 
     progressCallback(completedPercentage: counter/total) 
     dispatch_group_leave(downloadGroup) 
    } 
} 

dispatch_group_notify(downloadGroup, dispatch_get_main_queue()) { 
    if myData.count == urls.count { 
     println("All data retrieved") 
    } 
} 

为了把这个代码单词,它基本上只是从网络上下载东西,并将其添加到数组中。只有下载完所有数据后,才会调用代码dispatch_group_notify()的最后一部分。

有趣的部分是,myData.count == urls.count返回true,这意味着关闭被执行,但counter总是0。我的猜测是[]是线程安全的,而Int不是。

我该如何解决这个问题?我已经试过thisthis,它不起作用。

回答

0

为什么不使用NSLock来防止多线程尝试访问您的“关键部分”。你甚至可以摆脱派遣组像这样做:

let lock = NSLock() 
counter = 0 // Why was this a float shouldn't it be an Int? 
total = urls.count // This one too? 

var myData = [MyData]() 

for url in urls { 
    dispatch_group_enter() 
    process.doAsync(url) { data in 
     // Since this code is on the main queue, fetch another queue cause we are using the lock. 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { 
      lock.lock() 
      myData.append(data) // Append data from url to an array 
      ++counter 
      // Check inside the critical section only. 
      if myData.count == urls.count { 
       println("All data retrieved") 
       // Do your stuff here get the main queue if required by using dispatch_async(dispatch_get_main_queue(), { }) 
      } 
      lock.unlock() 
     }) 
     // Do the rest on the main queue. 
     progressCallback(completedPercentage: counter/total) 
    } 
}