修改一个新数组然后崩溃

时间:2018-12-03 15:35:36

标签: swift thread-safety

var list: [Int] = []
public func printListValues() {
    DispatchQueue.global().async {
        while true {
            if self.list.count < 10 {
                self.list.append(self.list.count)
            } else {
                self.list.removeAll()
            }
        }
    }

    DispatchQueue.global().async {
        while true {
            let newList = self.list
             newList.forEach { debugPrint($0) }

        }
    }

}

我知道有时数组不是线程安全的。但是我做了let value = self.list。而且它还会崩溃并显示以下信息:

  

线程3:致命错误:索引超出范围

newList.forEach { debugPrint($0) }行上。

为什么newList不安全。有什么问题吗?

2 个答案:

答案 0 :(得分:2)

数组操作不是原子的。当您在第二个线程中访问数组时,必须确保它不在第一个线程上的append()或removeAll()操作的中间,否则您可能正在复制处于不确定状态的数组。类似地,这两个操作之一可能发生在数组复制操作的中间,这会导致在复制数组时更改状态的问题。您可以通过添加一些线程同步来修复代码。

var list: [Int] = []
var mutex = pthread_mutex_t()
public func printListValues() {
    pthread_mutex_init(&mutex, nil)
    DispatchQueue.global().async {
        while true {
            if self.list.count < 10 {
                pthread_mutex_lock(&self.mutex)
                self.list.append(self.list.count)
                pthread_mutex_unlock(&self.mutex)
            } else {
                pthread_mutex_lock(&self.mutex)
                self.list.removeAll()
                pthread_mutex_unlock(&self.mutex)
            }
        }
    }

    DispatchQueue.global().async {
        while true {
            pthread_mutex_lock(&self.mutex)
            let newList = self.list
            pthread_mutex_unlock(&self.mutex)
            newList.forEach { debugPrint($0) }
        }
    }
}

答案 1 :(得分:2)

@Spads提供了有关该问题的大量信息(尽管我将使用GCD而不是pthread来解决该问题),但它提出了一个问题,即如果您没有立即发现问题,则如何发现此问题。答案是Thread Sanitizer,它将直接指向您的问题所在。这是方案的一项设置(或者您可以直接将extractData传递到 function this = extractData(this, xAxis, yAxis) s = dir('*.txt'); % Gather all text files disp(length(s)) for i=1:length(s) % Loop through and gather data until last element of strcuct j = 1; fid = s(i).name; % Open file in read-only mode this = this.readDataFromFile(fid); disp(fid) x = this.metaData(find(contains(this.metaData(:,1), xAxis)),3); this.temp(i,j) = x; disp(this.temp(i,j)) j = j+1; y = this.metaData(find(contains(this.metaData, yAxis)),3); %#ok<*FNDSB> this.temp(i,j) = y; disp(this.temp(i,j)) end %for end %extractData )。

Thread Sanitizer setting in Xcode

设置完成后,您将在Xcode中获得以下内容,直接将您指向冲突的行。

enter image description here