I want to create thread-safe array for piping data between threads
public class SyncArray<T> {
public var dataArray = [T]()
private var semaphore = DispatchSemaphore(value: 1)
public init() {
}
private func wait() { semaphore.wait() }
private func signal() { semaphore.signal() }
public func count() -> Int {
var count = 0;
wait(); defer { signal() }
count = dataArray.count
return count;
}
public func unshift() -> T? {
var firstEl:T? = nil
wait(); defer { signal() }
if(self.count() > 0){
firstEl = dataArray.removeFirst()
}
return firstEl;
}
public func pop() -> T? {
var lastEl:T? = nil
wait(); defer { signal() }
if(self.count() > 0){
lastEl = dataArray.popLast()
}
return lastEl;
}
public func append(value: T) -> Void {
wait(); defer { signal() }
dataArray.append(value)
}
}
Pipe data
let buff = SyncArray<Container>()
DispatchQueue.global().async {
do {
let dataSource = getDataSource()
for i in 0 ..< dataSource.length{
buff.append(value: dataSource[i])
}
}
DispatchQueue.global().async {
while(true) {
let data = buff.unshift()
}
}
The idea is to pipe data between threads. For some reason buff.append
and buff.unshift
deadlocks eachother
i tried allso
public func count() -> Int {
wait();
count = dataArray.count
signal()
return count;
}
Same result. Please, advise what am I doing wrong. I feel the fix should be super simple. Thanks!
CodePudding user response:
Your problem is that unshift
calls count
. unshift
is already holding the semaphore, but the first thing that count
does is call wait
, which causes a deadlock. You have the same problem in popLast
.
Since you already have exclusive access to the array you can simply use its isEmpty
property.
public func unshift() -> T? {
var firstEl:T? = nil
wait(); defer { signal() }
if !dataArray.isEmpty {
firstEl = dataArray.removeFirst()
}
return firstEl;
}
public func pop() -> T? {
var lastEl:T? = nil
wait(); defer { signal() }
if !dataArray.isEmpty {
lastEl = dataArray.popLast()
}
return lastEl;
}
You could also replace your DispatchSemaphore
with a NSRecursiveLock
since you don't need the counting behaviour of a semaphore. NSRecursiveLock
can be lock
ed multiple times by the same thread without causing a deadlock.