2015-07-03 39 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) 
    } 
}