Измените новый массив, затем вылетите - PullRequest
0 голосов
/ 03 декабря 2018
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 голосов
/ 03 декабря 2018

@ Спадс имеет отличную информацию о проблеме (хотя для ее решения я бы использовал GCD, а не pthreads), но возникает вопрос о том, как вы это обнаружите, если сразу не увидите проблему.Ответ - средство для дезинфекции нитей, которое укажет вам, где ваша проблема.Это настройка на схеме (или вы можете передать -sanitizer=thread на swiftc напрямую).

Thread Sanitizer setting in Xcode

С этим набором вы получите следующее в Xcode, указывая вамнепосредственно на линии, которые конфликтуют.

enter image description here

0 голосов
/ 03 декабря 2018

Операции с массивами не являются атомарными.Когда вы обращаетесь к массиву во втором потоке, вы должны быть уверены, что он не находится в середине операции 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) }
        }
    }
}
...