Альтернативы Mutex в быстрой

У меня есть разделяемая память между несколькими потоками. Я хочу, чтобы эти потоки не обращали внимание на эту часть памяти одновременно. (например, проблема производителя-потребителя)

Проблема

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

Одним из решений этой проблемы является использование Mutex.

Как я нашел, в Swift нет Mutex. Есть ли альтернативы в Swift?

Ответ 1

Как люди прокомментировали (включая меня), есть несколько способов добиться такого блокирования. Но я думаю, что семафор отправки лучше других, потому что он, по-видимому, имеет наименьшие издержки. Как найдено в Apples doc, "Замена кода семафора" , он не переходит в пространство ядра, если семафор уже заблокирован (= ноль), что является единственным случаем, когда код переходит в ядро ​​для переключения потока. Я думаю, что семафор не ноль большую часть времени (что, конечно же, относится к конкретным приложениям). Таким образом, мы можем избежать множества накладных расходов.

Еще один комментарий к отправке семафора, который является противоположным сценарием выше. Если ваши потоки имеют разные приоритеты выполнения, а потоки с более высоким приоритетом должны блокировать семафор в течение длительного времени, семафор отправки может не быть решением. Это связано с тем, что среди ожидающих потоков нет "очереди". Что происходит в этом случае, так это то, что более высокий приоритет потоки получают и блокируют семафор большую часть времени, а потоки с более низким приоритетом могут блокировать семафор только изредка, поэтому, в основном, просто ждут. Если это поведение не подходит для вашего приложения, вы должны вместо этого рассмотреть очередь отправки.

Ответ 2

Есть много решений для этого, но я использую последовательные очереди для такого рода действий:

let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync { 
    //call some code here, I pass here a closure from a method
}

Редактировать/Обновить: также для семафоров:

let higherPriority = DispatchQueue.global(qos: .userInitiated)
let lowerPriority = DispatchQueue.global(qos: .utility)

let semaphore = DispatchSemaphore(value: 1)

func letUsPrint(queue: DispatchQueue, symbol: String) {
    queue.async {
        debugPrint("\(symbol) -- waiting")
        semaphore.wait()  // requesting the resource

        for i in 0...10 {
            print(symbol, i)
        }

        debugPrint("\(symbol) -- signal")
        semaphore.signal() // releasing the resource
    }
}

letUsPrint(queue: lowerPriority, symbol: "Low Priority Queue Work")
letUsPrint(queue: higherPriority, symbol: "High Priority Queue Work")

RunLoop.main.run()

Ответ 3

Благодаря комментарию beshio вы можете использовать семафор следующим образом:

let semaphore = DispatchSemaphore(value: 1)

используйте wait перед использованием ресурса:

semaphore.wait()
// use the resource

и после использования release:

semaphore.signal()

Сделайте это в каждом потоке.