执行swift的同步不起作用

时间:2018-03-19 15:03:19

标签: swift multithreading concurrency

我是swift的新手,我正在尝试使用多线程技术,这个概念在swift中似乎并不出名。根据java synchronized实现的this示例,我尝试根据为another SO帖子上的swift提供的示例为swift做同样的事情。这是我的实施:

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

public class TestThread {
    var name : String;
    var theDemo : TheDemo;
    init(_ name : String, _ theDemo : TheDemo) {
        self.theDemo = theDemo;
        self.name = name;
        run()
    }

    public func run() {
        DispatchQueue.global(qos: .background).async {
            DispatchQueue.main.async {
                self.theDemo.testSynced(self.name)
            }
        }
    }
}

public class TheDemo {
    private func synced(_ lock : Any, _ name : String, _ closure : (_ name : String) -> ()){
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        closure(name)

    }
    public func testSynced(_ name : String){
        synced(self, name, test)
    }
    public func test(_ name : String) {
        for i in 0..<4 {
            let str = "\(name) :: \(i)"
            let theDeadline = DispatchTime.now() + .seconds(i/2)
            DispatchQueue.main.asyncAfter(deadline: theDeadline, execute: {
                print(str)
            })
        }
    }

}

var theDemo = TheDemo()
TestThread("THREAD 1", theDemo)
TestThread("THREAD 2", theDemo)
TestThread("THREAD 3", theDemo)
TestThread("THREAD 4", theDemo)

当我在操场上运行上面的代码时,我得到的结果如下所示

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 4 :: 0
THREAD 4 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 4 :: 2
THREAD 4 :: 3

但我期待的结果如下所示。

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 4 :: 0
THREAD 4 :: 1
THREAD 4 :: 2
THREAD 4 :: 3

我希望了解我做错了什么。考虑到同步和快速线程的概念,我是否也在正确的道路上设定了我的期望。我很感激帮助。感谢。

修改

由于我认为自己被误解了,所以我想解释一下我想做的事情。我基本上想要实现的是与我在代码中所写的有点不同。这是一个简化版本。如果synchronized在一个简单的例子中工作,我想测试它,然后我想在另一个项目中使用它。我正在将为android编写的项目翻译成ios。在java多线程中,我使用synchronized,因此一次只有一个线程可以使用该函数。让我们说多个线程可以使用的变量或函数。当我在函数名或变量名之前放置synchronized时,线程将有一个锁。现在在我的项目中,我有几个线程,基于一些传感器输入来来去去 - 在它们死之前它们使用了一个共同的共享功能。他们可以随时来。由于多种原因,我们设置了常用函数synchronized,以便没有两个线程同时进入该函数。因此,当我翻译代码时,我在swift中查找了类似的内容,并找到了与此问题相关联的链接之一。我尝试使用它 - 它对我没用。错误是人 - 我可能在某处犯了错误。但我花时间根据我的日程安排阅读。 (我部分地说多线程在swift中并不是很有名,因为我读过一些地方this

2 个答案:

答案 0 :(得分:1)

问题

TheDemo

let theDeadline = DispatchTime.now() + .seconds(i/2)
DispatchQueue.main.asyncAfter(deadline: theDeadline, execute: {
    self.theDemo.testSynced(self.name)


<强>解决方案

TestThread

DispatchQueue.global(qos: .background).async {
        let theDeadline = DispatchTime.now() + .seconds(1)
        DispatchQueue.main.asyncAfter(deadline: theDeadline, execute: {

TheDemo

for i in 0..<4 {
    let str = "\(name) :: \(i)"
    print(str)
}


说明

因此。每个异步任务都完成得非常快,以至于它们从现在起被推迟到同一时间。您可以深入了解DispatchQueue的主线程如何在您同时执行所有操作时处理这种情况。

//Starts at some exact time

TestThread("THREAD 1", theDemo)
TestThread("THREAD 2", theDemo)
TestThread("THREAD 3", theDemo)
TestThread("THREAD 4", theDemo)

//Finishes at the same exact time.  Too fast!
//

在我的解决方案中,打印是在单个时间上下文中(操作员的主队列,您可以在其中创建所有自定义线程)。因此它按照您的预期打印。您将不得不使用更精细的单位(没有[纳秒])或设计它与我向您展示的略有不同。

答案 1 :(得分:1)

首先,不要在操场上测试这些东西,因为它的输出不能正确模拟现实。在实际的应用项目中测试。

其次,摆脱这一切:

    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    closure(name)

做任何你想要纯粹使用GCD的事情。

我不清楚你想做什么; objc_sync_enterasyncAfter的混乱对我来说太神秘了。然而,这些东西一点都不神秘,并且有很好的记录和解释(与你的说法相反)。

从您想要的输出中,看起来您想要排队“线程1”操作并让它在“线程2”操作开始之前从头到尾运行。

  • 保证将这些操作排入串行队列的一种方法,因为这意味着排队的操作在其前面的队列为空之前无法启动。这在代码中没有发生,因为您的队列是并发队列,这意味着操作同时运行 (即它们的步骤可以相互交错)。
  • 另一种方法是使用sync而不是async调用“线程1”操作,因为这意味着您的代码会等待(阻塞),直到操作完成并返回。

以下是第一种方式的示例,我认为这是更好的方法:

let queue = DispatchQueue(label:"myqueue") // serial queue
func go() {
    for i in 0..<4 {
        let name = "Thread \(i)"
        queue.async {
            for i in 0..<4 {
                let str = "\(name) :: \(i)"
                print(str)
            }
        }
    }
}

我们致电go()时的输出:

Thread 0 :: 0
Thread 0 :: 1
Thread 0 :: 2
Thread 0 :: 3
Thread 1 :: 0
Thread 1 :: 1
Thread 1 :: 2
Thread 1 :: 3
Thread 2 :: 0
Thread 2 :: 1
Thread 2 :: 2
Thread 2 :: 3
Thread 3 :: 0
Thread 3 :: 1
Thread 3 :: 2
Thread 3 :: 3

这看起来很像你说的你想要的。