Синхронизация между разными потоками в Swift - PullRequest
0 голосов
/ 05 мая 2020

Может ли кто-нибудь дать совет о том, как блокировать потоки в Swift? В частности, у меня есть код, отделяющий модель от представления. Модель обрабатывает добавление, обновление и удаление по отдельности перед фиксацией для доступа к представлению. У меня есть код, который работает в фоновом потоке, чтобы основной поток оставался красивым и быстрым. Приведенный ниже пример кода похож на тот, что я реализовал, и он работает. Однако меня беспокоит, что это слишком сложно с DispatchQueue и блокировками. Я не знаю лучшего способа блокировки между потоками, и это, кажется, работает, но я уверен, что кто-то умнее меня может показать более элегантное решение? Приветствуются любые советы.

class MyClass {
    private let model = MyDataModel()
    private let syncQueue = DispatchQueue(label: "MyClass")
    private let lock = NSLock()  

    /**
        This function can be called from several different places on several different threads.
    */
    func processAdds() {
        assert(!Thread.isMainThread)

        // Ensure no other thread sneaks in and modifies the model while we're working.
        syncQueue.sync {
            self.lock.lock() // Is this overkill?

            // Modify the model.
            self.model.calculatePendingAdds()

            // Commit the model.
            self.model.commit()

            // Do some long running stuff with the committed data.
            self.model.doStuff()

            DispatchQueue.main.async {
                self.updateTheUI() // Must be done on the main thread but we don't want another background thread sneaking in and modifying the model.

                // Only release the lock when this main thread async block is finished.
                self.lock.unlock() // I think this is not overkill because I can't exit the syncQueue before the main thread is finished updating the UI.
            }
    } 

    /**
        This function can be called from several different places on several different threads.
    */
    func processDeletes() {
        assert(!Thread.isMainThread)

        // Ensure no other thread sneaks in and modifies the model while we're working.
        syncQueue.sync {
            self.lock.lock() // Is this overkill?

            // Modify the model.
            self.model.calculatePendingDeletes()

            // Commit the model.
            self.model.commit()

            // Do some long running stuff with the committed data.
            self.model.doStuff()

            DispatchQueue.main.async {
                self.updateTheUI() // Must be done on the main thread but we don't want another background thread sneaking in and modifying the model.

                // Only release the lock when this main thread async block is finished.
                self.lock.unlock() // I think this is not overkill because I can't exit the syncQueue before the main thread is finished updating the UI.
            }
    } 
}

1 Ответ

0 голосов
/ 05 мая 2020

Покопавшись и попробовав немного поэкспериментировать, я понял, что использование настраиваемой очереди отправки с блокировкой действительно было излишним. Очередь отправки уже действует как блокировка, поэтому использование ее с блокировкой было избыточным. Мне действительно нужна была блокировка, которую можно было бы разблокировать в другом потоке, поэтому я решил, что мьютекс лучше. Я избавился от настраиваемой очереди и блокировки и заменил их на это:

class MyClass {
    private let model = MyDataModel()
    private let mutex = pthread_mutex_t()

    /**
        This function can be called from several different places on several different threads.
    */
    func processAdds() {
        assert(!Thread.isMainThread)

        // Ensure no other thread sneaks in and modifies the model while we're working.
        pthread_mutex_lock(&self.mutex)

        // Modify the model.
        self.model.calculatePendingAdds()

        // Commit the model.
        self.model.commit()

        // Do some long running stuff with the committed data.
        self.model.doStuff()

        DispatchQueue.main.async {
            self.updateTheUI() // Must be done on the main thread but we don't want another background thread sneaking in and modifying the model.

            // Only release the lock when this main thread async block is finished.
            pthread_mutex_unlock(&self.mutex)
        }
    } 

    /**
        This function can be called from several different places on several different threads.
    */
    func processDeletes() {
        assert(!Thread.isMainThread)

        // Ensure no other thread sneaks in and modifies the model while we're working.
        pthread_mutex_lock(&self.mutex)

        // Modify the model.
        self.model.calculatePendingDeletes()

        // Commit the model.
        self.model.commit()

        // Do some long running stuff with the committed data.
        self.model.doStuff()

        DispatchQueue.main.async {
            self.updateTheUI() // Must be done on the main thread but we don't want another background thread sneaking in and modifying the model.

            // Only release the lock when this main thread async block is finished.
            pthread_mutex_unlock(&self.mutex)
        }
    } 
}

Кажется простым и работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...