全部中止 dispatch_semaphore_wait
Abort all dispatch_semaphore_wait
在 iOS 中,GCD 提供信号量来同步访问有限的资源。
在我的程序中,我正在从外部设备读取数据。该外部设备可以断开连接,程序将永远不会再向信号量发出信号。所以我们最终会遇到以下情况:
线程 1 正在等待信号量
if (dispatch_semaphore_wait(self.writeSem, /* 15s timeout */)) {
线程2知道不等待会成功
最终,dispatch_semaphore_wait
超时,returns NO
并且线程 1 恢复 运行。
我怎样才能立即使这个 dispatch_semaphore_wait
失败,以便线程 1 立即获得 NO
并继续他的生命?我可以使用某种 "cancel semaphore" 吗?
没有额外的 "machinery" 信号量是错误的抽象。没有 "cancel semaphore wait" 除了发出信号之外的操作,并且在发出信号时,没有更多信息,您不知道它是因为成功还是终止而发出信号。所以你可以添加一个外部标志来指示信号是完成还是提前终止,但是你必须适当地保护该标志以防止并发读取和写入。
这里使用的规范原语是条件变量,标准 Cocoa 示例将使用 NSCondition。一个简单的示例可能如下所示:
NSCondition* cond = [NSCondition new];
__block BOOL workSucceeded = NO;
__block BOOL subordinateFinished = NO;
NSTimeInterval timeout = 5.0;
// Waiter
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[cond lock];
while (!subordinateFinished)
{
if (![cond waitUntilDate: [NSDate dateWithTimeIntervalSinceNow: timeout]])
{
// Timed out...
NSLog(@"Timed out waiting for work at: %@", [NSDate date]);
break; // don't keep waiting
}
else if (workSucceeded)
{
// Signaled to indicate that work was done
NSLog(@"Work finished at: %@", [NSDate date]);
}
else //if (!workSucceeded)
{
// Signaled to indicate premature termination.
NSLog(@"Work prematurely terminated at: %@", [NSDate date]);
}
}
[cond unlock];
});
// Actor
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"Work started at: %@", [NSDate date]);
BOOL completed = NO;
// Uncomment one of these to trigger each case
// Finish on time:
//sleep(1);
//completed = YES;
// Fail Early:
//sleep(1);
// Time out
//sleep(timeout + 1);
// ... and when done
[cond lock];
workSucceeded = completed;
subordinateFinished = YES;
[cond signal];
[cond unlock];
});
这里要理解的重要一点是 workSucceeded
和 subordinateFinished
受到条件锁的保护,任何不持有锁的人都不会读取或写入。第一次使用 NSCondition 的人通常不清楚的是,调用 -wait
、-waitUntilDate:
或 -signal
的行为都会导致调用线程暂时 [=25] =] 放弃锁,理解为当该线程恢复执行时,它将再次持有锁。
希望对您有所帮助。
在 iOS 中,GCD 提供信号量来同步访问有限的资源。
在我的程序中,我正在从外部设备读取数据。该外部设备可以断开连接,程序将永远不会再向信号量发出信号。所以我们最终会遇到以下情况:
线程 1 正在等待信号量
if (dispatch_semaphore_wait(self.writeSem, /* 15s timeout */)) {
线程2知道不等待会成功
最终,dispatch_semaphore_wait
超时,returns NO
并且线程 1 恢复 运行。
我怎样才能立即使这个 dispatch_semaphore_wait
失败,以便线程 1 立即获得 NO
并继续他的生命?我可以使用某种 "cancel semaphore" 吗?
没有额外的 "machinery" 信号量是错误的抽象。没有 "cancel semaphore wait" 除了发出信号之外的操作,并且在发出信号时,没有更多信息,您不知道它是因为成功还是终止而发出信号。所以你可以添加一个外部标志来指示信号是完成还是提前终止,但是你必须适当地保护该标志以防止并发读取和写入。
这里使用的规范原语是条件变量,标准 Cocoa 示例将使用 NSCondition。一个简单的示例可能如下所示:
NSCondition* cond = [NSCondition new];
__block BOOL workSucceeded = NO;
__block BOOL subordinateFinished = NO;
NSTimeInterval timeout = 5.0;
// Waiter
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[cond lock];
while (!subordinateFinished)
{
if (![cond waitUntilDate: [NSDate dateWithTimeIntervalSinceNow: timeout]])
{
// Timed out...
NSLog(@"Timed out waiting for work at: %@", [NSDate date]);
break; // don't keep waiting
}
else if (workSucceeded)
{
// Signaled to indicate that work was done
NSLog(@"Work finished at: %@", [NSDate date]);
}
else //if (!workSucceeded)
{
// Signaled to indicate premature termination.
NSLog(@"Work prematurely terminated at: %@", [NSDate date]);
}
}
[cond unlock];
});
// Actor
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"Work started at: %@", [NSDate date]);
BOOL completed = NO;
// Uncomment one of these to trigger each case
// Finish on time:
//sleep(1);
//completed = YES;
// Fail Early:
//sleep(1);
// Time out
//sleep(timeout + 1);
// ... and when done
[cond lock];
workSucceeded = completed;
subordinateFinished = YES;
[cond signal];
[cond unlock];
});
这里要理解的重要一点是 workSucceeded
和 subordinateFinished
受到条件锁的保护,任何不持有锁的人都不会读取或写入。第一次使用 NSCondition 的人通常不清楚的是,调用 -wait
、-waitUntilDate:
或 -signal
的行为都会导致调用线程暂时 [=25] =] 放弃锁,理解为当该线程恢复执行时,它将再次持有锁。
希望对您有所帮助。