【问题标题】:Is there any way of locking an object in Swift like in C#有什么方法可以像 C# 一样在 Swift 中锁定对象
【发布时间】:2015-06-30 11:00:44
【问题描述】:

我有以下代码:

func foo() {
    var sum = 0
    var pendingElements = 10

    for i in 0 ..< 10 {
        proccessElementAsync(i) { value in
            sum += value
            pendingElements--

            if pendingElements == 0 {
                println(sum)
            }
        }
    }
}

在这种情况下,函数proccessElementAsync,顾名思义,异步处理其输入参数,并在完成时调用其相应的完成处理程序。

这种方法的不便之处在于,由于变量 pendingElements 是通过多个线程访问的,那么语句 if pendingElements == 0 可能永远不会具有值 true。

在 C# 中,我们可以执行以下操作:

Object lockObject = new Object();
...

lock (lockObject) {
    pendingElements--;

    if (pendingElements == 0) {
        Console.WriteLine(sum);
    }
}

这确保了这个变量只能同时被一个线程访问。有什么方法可以在 Swift 中获得相同的行为?

【问题讨论】:

  • 旁注:在 C# 中lock(someIntValue) 不会做任何与您试图实现的目标很接近的事情...在 C# 中,请考虑遵循创建仅用于锁定的特殊对象的默认准则...跨度>
  • 在 C# 中我们可以做到Interlocked.Decrement
  • @AlexeiLevenkov 我已经更新了 c# 代码,我认为我对它太不正式了。对此感到抱歉
  • @ReynaldoAguilar - 现在看起来不错。一般来说,请记住,读者不可能区分“非正式/快速编写的示例”和“对概念的完全误解”。因此,显示正确的代码可以显着提高回答实际解决您正在寻找的内容的机会。

标签: swift multithreading


【解决方案1】:

没有本机锁定工具,但有类似这个 SO 问题中解释的解决方法:

What is the Swift equivalent to Objective-C's "@synchronized"?

使用其中一个答案,您可以创建一个函数:

    func synchronize(lockObj: AnyObject!, closure: ()->()){
        objc_sync_enter(lockObj)
        closure()
        objc_sync_exit(lockObj)
    }

然后:

     func foo() {
        var sum = 0
        var pendingElements = 10

        for i in 0 ..< 10 {
            processElementAsync(i) { value in

                synchronize(pendingElements) {
                    sum += value
                    pendingElements--

                    if pendingElements == 0 {
                        println(sum)
                    }
                }

            }
        }
    }

【讨论】:

    【解决方案2】:

    希望这会对你有所帮助。

    func lock(obj: AnyObject, blk:() -> ()) {
        objc_sync_enter(obj)
        blk()
        objc_sync_exit(obj)
    }
    
    var pendingElements = 10
    
    func foo() {
        var sum = 0
        var pendingElements = 10
    
        for i in 0 ..< 10 {
            proccessElementAsync(i) { value in
    
                lock(pendingElements) {
                    sum += value
                    pendingElements--
    
                    if pendingElements == 0 {
                        println(sum)
                    }
                }
    
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复。如果调用 objc_sync_enter(obj) 和 objc_sync_exit 做我相信的事情,那么你的回答解决了我的问题。您能否在答案中添加一些有关这些功能的作用的详细信息?我认为这将提高答案的质量
    • 我从苹果的文档中得到了objc_sync_enter和exit的信息。 objc_sync_enter(id obj) : 在 'obj' 上开始同步。如果需要,分配与 'obj' 关联的递归 pthread_mutex。 int objc_sync_exit(id obj): 在 'obj' 上结束同步。
    • 仅针对其他人,我建议使用更强大的版本func synchronized(object:AnyObject!, @noescape _ closure: () throws -&gt; ()) rethrows { objc_sync_enter(object) defer { objc_sync_exit(object) } try closure() }
    • this answer中查看更通用的选项
    • 这对于简单的事情非常有用,但是如果你想在锁内做一个提前返回,你不能(你的返回只是从锁作用域返回,而不是从 foo() 函数返回) . 不幸:-(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    相关资源
    最近更新 更多