0

似乎不要等待小组的结束

let oneSem_1 = DispatchSemaphore(value: 1)
let semaphore = DispatchSemaphore(value: 4)
let semaphoreEND = DispatchSemaphore(value: 0)
var p=0
let group_2 = DispatchGroup()
var t:[Int]=[]
let MAX=1000000
for _ in 0..<MAX {
    group_2.enter()
    DispatchQueue.global().async{
        //group_2.enter()
        semaphore.wait()

        oneSem_1.wait()
        p+=1
        t.append(p)//car ressource critique, sinon pas rempli à fond
        oneSem_1.signal()

        if p == MAX{
            print("p == MAX")
            semaphoreEND.signal()
        }

        semaphore.signal()
        //group_2.leave()
    }
    group_2.leave()
}

group_2.wait()
//    semaphoreEND.wait()

//    while(p != MAX){
//        usleep(1_00_000)
//        print("p=",p)
//    }
print("END   p=\(p)  t.count=\(t.count)")

我期望 ND p=1000000 t.count=1000000 的输出

如果我取消注释 // semaphoreEND.wait() 我可以得到这个结果

,但实际输出是

结束 p=999871 t.count=999881

其他问题:t.count != p

对于 Group,我希望所有任务都结束。为什么我必须取消注释 // semaphoreEND.wait() ?

谢谢

项目在这里下载:https ://github.com/fredOnGitHub/semaphore_to_modify_1

4

3 回答 3

0

这个问题的另一个解决方案(没有等待组)

using Apple Processes and Threads > RunLoop :: 根据vadian委员会

请参阅等待任务完成Fundation > Processes-And-Threads > RunLoop

// Store a reference to the current run loop
var shouldKeepRunning = true
let runLoop = RunLoop.current
func task(){
    //sleep(1)
    oneSem_1.wait()
    p+=1
    t.append(p)//ressource critique, sinon pas rempli à fond
    if p == MAX{
        print("p == MAX")
//        shouldKeepRunning = false//BUG!!
        DispatchQueue.main.async{//METTRE CECI
            shouldKeepRunning = false
        }
    }
    oneSem_1.signal()
}
for _ in 0..<MAX {
    DispatchQueue.global().async{
        semaphore.wait()
        //print("wake up")
        task()
        //print("end")
        semaphore.signal()
    }
}
// Start run loop after work has been started
print("start")
while shouldKeepRunning  && runLoop.run(mode: .default, before: .distantFuture)
{
    print("WROTE ONLY ONCE")

}
print("END   p=\(p)  t.count=\(t.count)")

备注:

苹果在这里说“RunLoop 类通常不被认为是线程安全的,它的方法只能在当前线程的上下文中调用。你永远不应该尝试调用在不同线程中运行的 RunLoop 对象的方法,因为这样做可能会导致意想不到的结果。”

并举个例子。这里的变化是:

  1. 使用变量更多
  2. 必须使用DispatchQueue.main.async{仅此而已

我想知道这两种解决方案之间的最佳选择,因为即使您有更多变量,它也继承自Threads > RunLoop

于 2019-09-06T08:37:07.003 回答
0

此问题的另一种解决方案(无需等待组):根据vadian委员会

请参阅如何退出运行循环?,核心基础 > CFRunLoop

let oneSem_1 = DispatchSemaphore(value: 1)
let semaphore = DispatchSemaphore(value: 4)
var p=0
var t:[Int]=[]
let MAX=100_000
#if DEBUG
print("DEBUG")
// Store a reference to the current run loop
let runLoop = CFRunLoopGetCurrent()
#endif

func task(){
    //sleep(1)
    oneSem_1.wait()
    p+=1
    t.append(p)//ressource critique, sinon pas rempli à fond
    if p == MAX{
        #if DEBUG
        print("CFRunLoopStop(runLoop)")
        CFRunLoopStop(runLoop)
        #else
        DispatchQueue.main.async{
            print("CFRunLoopStop(CFRunLoopGetCurrent())")
            CFRunLoopStop(CFRunLoopGetCurrent())
        }
        #endif
    }
    oneSem_1.signal()
}
for _ in 0..<MAX {
    DispatchQueue.global().async{
        semaphore.wait()
//        print("wake up")
        task()
//        print("end")
        semaphore.signal()
    }
}
// Start run loop after work has been started
print("start")
CFRunLoopRun()
print("END   p=\(p)  t.count=\(t.count)")

备注:

如果你想使用 CFRunLoopStop(CFRunLoopGetCurrent()) 它在 DispatchQueue.main.async{ 否则你必须初始化 let runLoop = CFRunLoopGetCurrent() 并且你可以直接做 CFRunLoopStop(runLoop) 如果已经创建了很多这不是问题的线程。也许这就是为什么 Apple 说“......CFRRun 循环可以递归运行......”

于 2019-09-06T08:14:59.073 回答
0

此问题的解决方案:

我把 group_2.leave() 放在一个不好的地方。就像这里等待任务完成&& GCD 解释和其他类似2. DispatchGroup你必须把它放在他完成的异步函数中

func task(){
//    sleep(1)
    oneSem_1.wait()
    p+=1
    t.append(p)//car ressource critique, sinon pas rempli à fond
    oneSem_1.signal()
}

print("start")
for _ in 0..<MAX {
    group_2.enter()
    DispatchQueue.global().async{
        semaphore.wait()
//        print("wake up")
        task()
//        print("end")
        group_2.leave()
        semaphore.signal()
    }
}
group_2.wait()
print("END   p=\(p)  t.count=\(t.count)")

使用此解决方案,我不需要测试 p == MAX 是否可以解锁数组的最终打印(semaphoreEND.signal())

然而,vadian有一个很好的注释“不,你必须明确地启动和停止运行循环。”

我在找这个实现,太神奇了,退出

于 2019-09-05T20:19:06.167 回答