1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Foundation
#if os(Windows)
import WinSDK
#endif
/// This class bridges the gap between Darwin and Linux Foundation Threading API.
/// It provides closure based execution and a join method to block the calling thread
/// until the thread is finished executing.
final public class Thread {
/// The thread implementation which is Foundation.Thread on Linux and
/// a Thread subclass which provides closure support on Darwin.
private var thread: ThreadImpl!
/// Condition variable to support blocking other threads using join when this thread has not finished executing.
private var finishedCondition: Condition
/// A boolean variable to track if this thread has finished executing its task.
private var isFinished: Bool
/// Creates an instance of thread class with closure to be executed when start() is called.
public init(task: @escaping () -> Void) {
isFinished = false
finishedCondition = Condition()
// Wrap the task with condition notifying any other threads blocked due to this thread.
// Capture self weakly to avoid reference cycle. In case Thread is deinited before the task
// runs, skip the use of finishedCondition.
let theTask = { [weak self] in
if let strongSelf = self {
precondition(!strongSelf.isFinished)
strongSelf.finishedCondition.whileLocked {
task()
strongSelf.isFinished = true
strongSelf.finishedCondition.broadcast()
}
} else {
// If the containing thread has been destroyed, we can ignore the finished condition and just run the
// task.
task()
}
}
self.thread = ThreadImpl(block: theTask)
}
/// Starts the thread execution.
public func start() {
thread.start()
}
/// Blocks the calling thread until this thread is finished execution.
public func join() {
finishedCondition.whileLocked {
while !isFinished {
finishedCondition.wait()
}
}
}
/// Causes the calling thread to yield execution to another thread.
public static func yield() {
#if os(Windows)
SwitchToThread()
#else
sched_yield()
#endif
}
}
#if canImport(Darwin)
/// A helper subclass of Foundation's Thread with closure support.
final private class ThreadImpl: Foundation.Thread {
/// The task to be executed.
private let task: () -> Void
override func main() {
task()
}
init(block task: @escaping () -> Void) {
self.task = task
}
}
#else
// Thread on Linux supports closure so just use it directly.
typealias ThreadImpl = Foundation.Thread
#endif
|