gpt4 book ai didi

ios - 通过 Multipeer Framework 暂时同步两个客户端

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:22:03 24 4
gpt4 key购买 nike

我已经在这个问题上工作了几天,但我的解决方案都不合适。我认为我缺乏实现这一目标的理论知识,并且希望得到一些建议(不一定是特定于 iOS 的——我可以将 C、伪代码等翻译成我需要的)。

基本上,我有两部 iPhone。当用户按下按钮时,任何一个都可以触发重复操作。然后它需要通知另一部 iPhone(通过 MultiPeer 框架)触发相同的操作……但它们都需要同时启动并保持同步。我真的需要达到 1/100 秒的精度,我认为可以在此平台上实现。

作为对我的同步程度的半粗略衡量,我使用 AudioServices 在每台设备上播放“滴答”声……您可以很容易地通过耳朵判断它们的同步程度(理想情况下您会无法辨别多个声源)。

当然,我必须以某种方式考虑 MultiPeer 延迟......而且它的变化很大,在我的测试中从 0.1 秒到 0.8 秒不等。

在发现系统时钟对我的目的而言完全不可靠后,我找到了 NTP 的 iOS 实现并正在使用它。所以我有理由相信这两款手机有一个准确的时间共同引用(尽管我还没有想出一种方法来测试这个假设,除了在两个设备上连续显示 NTP 时间,我这样做了,而且看起来很好同步到我的眼睛)。

我之前尝试的是用 P2P 消息发送“开始时间”,然后(在接收端)从 1.5 秒常数中减去该延迟,并在该延迟后执行操作。在发件人端,我会简单地等待该常量过去,然后执行操作。这根本不起作用。我离题太远了。

我的下一次尝试是在两端等待整整一秒被三整除,因为延迟似乎总是 <1 秒,我认为这会奏效。我使用“延迟”方法来简单地阻塞线程。我知道这是一个大棒,但我只想在担心更优雅的解决方案之前获得计时工作时间。因此,我的“sender”(按下按钮的设备)执行以下操作:

-(void)startActionAsSender
{
[self notifyPeerToStartAction];
[self delay];
[self startAction];
}

接收者这样做是为了响应委托(delegate)调用:

-(void)peerDidStartAction
{
[self delay];
[self startAction];
}

我的“延迟”方法如下所示:

-(void)delay
{
NSDate *NTPTimeNow = [[NetworkClock sharedInstance] networkTime];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSSecondCalendarUnit
fromDate:NTPTimeNow];
NSInteger seconds = [components second];

// If this method gets called on a second divisible by three, wait a second...
if (seconds % 3 == 0) {
sleep(1);
}

// Spinlock
while (![self secondsDivideByThree]) {}
}

-(BOOL)secondsDivideByThree
{
NSDate *NTPTime = [[NetworkClock sharedInstance] networkTime];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger seconds = [[calendar components:NSSecondCalendarUnit fromDate:NTPTime]
second];

return (seconds % 3 == 0);
}

最佳答案

这是旧的,所以我希望你能得到一些工作。我遇到了一个非常相似的问题。在我的例子中,我发现不一致几乎完全是由于定时器合并导致定时器错误 by up to 10%在 iOS 设备上以节省电池使用量。

作为引用,这是我一直在自己的应用程序中使用的解决方案。首先,我使用一个简单的自定义协议(protocol),它本质上是一个基本的 NTP 等价物,用于同步本地网络上两个设备之间的单调递增时钟。我在下面的代码中将此同步时间称为“DTime”。使用此代码,我可以告诉所有同行“在时间 Y 执行操作 X”,并且它是同步发生的。

+ (DTimeVal)getCurrentDTime
{
DTimeVal baseTime = mach_absolute_time();
// Convert from ticks to nanoseconds:
static mach_timebase_info_data_t s_timebase_info;
if (s_timebase_info.denom == 0) {
mach_timebase_info(&s_timebase_info);
}
DTimeVal timeNanoSeconds = (baseTime * s_timebase_info.numer) / s_timebase_info.denom;
return timeNanoSeconds + localDTimeOffset;
}

+ (void)atExactDTime:(DTimeVal)val runBlock:(dispatch_block_t)block
{
// Use the most accurate timing possible to trigger an event at the specified DTime.
// This is much more accurate than dispatch_after(...), which has a 10% "leeway" by default.
// However, this method will use battery faster as it avoids most timer coalescing.
// Use as little as necessary.
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatch_get_main_queue());
dispatch_source_set_event_handler(timer, ^{
dispatch_source_cancel(timer); // one shot timer
while (val - [self getCurrentDTime] > 1000) {
// It is at least 1 microsecond too early...
[NSThread sleepForTimeInterval:0.000001]; // Change this to zero for even better accuracy
}
block();
});
// Now, we employ a dirty trick:
// Since even with DISPATCH_TIMER_STRICT there can be about 1ms of inaccuracy, we set the timer to
// fire 1.3ms too early, then we use an until(time) { sleep(); } loop to delay until the exact time
// that we wanted. This takes us from an accuracy of ~1ms to an accuracy of ~0.01ms, i.e. two orders
// of magnitude improvement. However, of course the downside is that this will block the main thread
// for 1.3ms.
dispatch_time_t at_time = dispatch_time(DISPATCH_TIME_NOW, val - [self getCurrentDTime] - 1300000);
dispatch_source_set_timer(timer, at_time, DISPATCH_TIME_FOREVER /*one shot*/, 0 /* minimal leeway */);
dispatch_resume(timer);
}

关于ios - 通过 Multipeer Framework 暂时同步两个客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23500364/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com