宽窄优行-由【嘉易行】项目成品而来
younger_times
2023-04-06 a1ae6802080a22e6e6ce6d0935e95facb1daca5c
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
100
101
102
//
//  AsyncLock.swift
//  RxSwift
//
//  Created by Krunoslav Zaher on 3/21/15.
//  Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
 
/**
In case nobody holds this lock, the work will be queued and executed immediately
on thread that is requesting lock.
 
In case there is somebody currently holding that lock, action will be enqueued.
When owned of the lock finishes with it's processing, it will also execute
and pending work.
 
That means that enqueued work could possibly be executed later on a different thread.
*/
final class AsyncLock<I: InvocableType>
    : Disposable
    , Lock
    , SynchronizedDisposeType {
    typealias Action = () -> Void
    
    var _lock = SpinLock()
    
    private var _queue: Queue<I> = Queue(capacity: 0)
 
    private var _isExecuting: Bool = false
    private var _hasFaulted: Bool = false
 
    // lock {
    func lock() {
        self._lock.lock()
    }
 
    func unlock() {
        self._lock.unlock()
    }
    // }
 
    private func enqueue(_ action: I) -> I? {
        self._lock.lock(); defer { self._lock.unlock() } // {
            if self._hasFaulted {
                return nil
            }
 
            if self._isExecuting {
                self._queue.enqueue(action)
                return nil
            }
 
            self._isExecuting = true
 
            return action
        // }
    }
 
    private func dequeue() -> I? {
        self._lock.lock(); defer { self._lock.unlock() } // {
            if !self._queue.isEmpty {
                return self._queue.dequeue()
            }
            else {
                self._isExecuting = false
                return nil
            }
        // }
    }
 
    func invoke(_ action: I) {
        let firstEnqueuedAction = self.enqueue(action)
        
        if let firstEnqueuedAction = firstEnqueuedAction {
            firstEnqueuedAction.invoke()
        }
        else {
            // action is enqueued, it's somebody else's concern now
            return
        }
        
        while true {
            let nextAction = self.dequeue()
 
            if let nextAction = nextAction {
                nextAction.invoke()
            }
            else {
                return
            }
        }
    }
    
    func dispose() {
        self.synchronizedDispose()
    }
 
    func _synchronized_dispose() {
        self._queue = Queue(capacity: 0)
        self._hasFaulted = true
    }
}