当前位置: 首页 > 面试题库 >

objc_sync_enter / objc_sync_exit无法与DISPATCH_QUEUE_PRIORITY_LOW一起使用

那绪
2023-03-14
问题内容

我需要为我的应用程序读/写锁。我已阅读
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

并写了我自己的类,因为在swift中没有读/写锁

class ReadWriteLock {

    var logging = true
    var b = 0
    let r = "vdsbsdbs" // string1 for locking
    let g = "VSDBVSDBSDBNSDN" // string2 for locking

    func waitAndStartWriting() {
        log("wait Writing")
        objc_sync_enter(g)
        log("enter writing")
    }


    func finishWriting() {
        objc_sync_exit(g)
        log("exit writing")
    }

    // ждет пока все чтение завершится чтобы начать чтение
    // и захватить мютекс
    func waitAndStartReading() {

        log("wait reading")
        objc_sync_enter(r)
        log("enter reading")
        b++
        if b == 1 {
            objc_sync_enter(g)
            log("read lock writing")
        }

        print("b = \(b)")
        objc_sync_exit(r)
    }


    func finishReading() {

        objc_sync_enter(r)

        b--

        if b == 0 {
            objc_sync_exit(g)
            log("read unlock writing")
        }

        print("b = \(b)")
        objc_sync_exit(r)
    }

    private func log(s: String) {
        if logging {
            print(s)
        }
    }
}

效果很好,直到我尝试从GCD线程使用它。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

当我尝试在某个时刻从不同的异步块使用此类时,它允许在写入被锁定时进行写入

这是示例日志:

wait reading
enter reading
read lock writing
b = 1
wait reading
enter reading
b = 2
wait reading
enter reading
b = 3
wait reading
enter reading
b = 4
wait reading
enter reading
b = 5
wait reading
enter reading
b = 6
wait reading
enter reading
b = 7
wait reading
enter reading
b = 8
wait reading
enter reading
b = 9
b = 8
b = 7
b = 6
b = 5
wait Writing
enter writing
exit writing
wait Writing
enter writing

因此,您可以看到g被锁定,但是objc_sync_enter(g)允许继续。为什么会发生这种情况?

顺便说一句,我检查了构造ReadWriteLock的次数,它是1。

为什么objc_sync_exit不能正常工作,并在未释放objc_sync_enter(g)时允许呢?

PS Readwirtelock定义为

class UserData {

    static let lock = ReadWriteLock()

谢谢。


问题答案:

objc_sync_enter是一个非常低级的原语,不能直接使用。这是@synchronizedObjC中旧系统的实现细节。即使那是非常过时的,通常也应该避免。

使用GCD队列可以最好地实现Cocoa中的同步访问。例如,这是一种实现读取器/写入器锁定(并行读取,互斥写入)的常用方法。

public class UserData {
    private let myPropertyQueue = dispatch_queue_create("com.example.mygreatapp.property", DISPATCH_QUEUE_CONCURRENT)

    private var _myProperty = "" // Backing storage
    public var myProperty: String {
        get {
            var result = ""
            dispatch_sync(myPropertyQueue) {
                result = self._myProperty
            }
            return result
        }

        set {
            dispatch_barrier_async(myPropertyQueue) {
                self._myProperty = newValue
            }
        }
    }
}

您的所有并发属性可以共享一个队列,也可以为每个属性分配自己的队列。这取决于您期望多少争用(作家将锁定整个队列)。


dispatch_barrier_async”中的“屏障”意味着它是当时唯一允许在队列上运行的事物,因此所有先前的读取将已完成,并且所有将来的读取将被阻止,直到完成为止。这种方案意味着您可以拥有任意数量的并发读取器,而不会饿死写入器(因为将始终为写入器提供服务),并且写入从不阻塞。仅当存在实际争用时,读取才被阻止。在正常情况下,这是非常快的。



 类似资料:
  • 问题内容: 我的程序应该等待按下向左或向右箭头键,然后更改一个值,以便下次更新PaintComponent时,屏幕看起来有所不同。但是,运行该程序时,屏幕没有变化。 以下是变量声明: 这是主要的KeyListener声明: 这是用于绘画的方法: 当我运行该程序时,该程序会打印外壳,但是当我按箭头键时,屏幕上没有任何变化。 问题答案: 您需要先将关键侦听器添加到组件,然后才能调用它: 您还需要使组件

  • 问题内容: click事件可以正常运行,但是onmouseover事件不起作用。 问题答案: 您需要大写一些字母。

  • 问题内容: 我在用Java做一个小Gui。我正在使用setBounds方法在JFrame上设置按钮等的位置,但是问题是,当我将JPanel按钮与JFrame一起使用时,在JFrame上不可见,并且如果没有JPanel也可以,请同时阅读代码,并请帮帮我我是初学者,正面临这些愚蠢的问题。 这个很好 当我将按钮添加到Jpanel时,相同的代码不起作用,所以怎么了,请指导我 请帮我解决这个小问题 问题答案

  • 我目前正在将IntelliJ IDE用于复杂的GWT项目。我想在GWT的开发模式中利用JRebel,所以最近我为IntelliJ安装了JRebel插件,但在使其工作时遇到了麻烦。 基本上IntelliJ不具备在更改时自动编译应用程序的能力,所以每当您对代码进行更改时,我都必须进行编译- 信息:使用JavaC1.7.0_21编译java源代码信息:15个错误信息:0个警告信息:编译完成,9分钟5秒内

  • 问题内容: 我使用以下代码将数据发送到MailChimp新闻列表(API v3)。每次我从函数中删除时,它都会尝试通过GET发布数据,并正确发送数据(在MailChimp API仪表板中可以确定响应)。在浏览器(FF)中进行测试时,我得到一个响应为“ true”的.part文件。 我将我的头发拔了出来,任何见识都将受到赞赏。 提前致谢, JN 问题答案: 主要问题是jc在您的原始帖子中评论了什么-

  • 问题内容: http://jsfiddle.net/YcK5X/ 我想知道为什么这个AJAX请求没有返回任何内容。 问题答案: 您想要echo:ed的数据必须在名为html的POST参数中提供: