Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 我可以使用Grand Central dispatch将任务分派到OSX DisplayLink线程吗?_Multithreading_Macos_Opengl_Grand Central Dispatch - Fatal编程技术网

Multithreading 我可以使用Grand Central dispatch将任务分派到OSX DisplayLink线程吗?

Multithreading 我可以使用Grand Central dispatch将任务分派到OSX DisplayLink线程吗?,multithreading,macos,opengl,grand-central-dispatch,Multithreading,Macos,Opengl,Grand Central Dispatch,在OSX下的OpenGL应用程序中,渲染代码通常在DisplayLink线程上运行,该线程与主线程分离 在后台执行任务(例如加载GL资源)时,同步线程非常重要,因此渲染线程不会尝试从后台线程正在积极更改的模型中绘制 在主线程上进行渲染时,我一直在使用GCD将后台任务的关键部分分派到主分派队列,如下所示: dispatch_async(dispatch_get_main_queue(), ^{ [self doCriticalThing]; }); 但是,当在DisplayLink线程上进行渲染

在OSX下的OpenGL应用程序中,渲染代码通常在DisplayLink线程上运行,该线程与主线程分离

在后台执行任务(例如加载GL资源)时,同步线程非常重要,因此渲染线程不会尝试从后台线程正在积极更改的模型中绘制

在主线程上进行渲染时,我一直在使用GCD将后台任务的关键部分分派到主分派队列,如下所示:

dispatch_async(dispatch_get_main_queue(), ^{ [self doCriticalThing]; });
但是,当在DisplayLink线程上进行渲染时,这不起作用,因为毫不奇怪,当DisplayLink尝试渲染时,在尝试运行关键任务的主线程之间会出现线程冲突

是否可以使用GCD将任务分派到DisplayLink线程而不是主线程

或者我是否需要恢复到使用以下内容:

performSelector:onThread:withObject:waitUntilDone:

要将任务直接分配给DisplayLink线程?

似乎没有任何内置API来实现这一点。不过,烹调起来相当简单。可能是这样的:

static CVReturn DispatchDisplayLinkOneshotCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext);

void dispatch_async_displaylink(CVDisplayLinkRef dl, dispatch_block_t block)
{
    if (!block || !dl)
        return;

    CVDisplayLinkRef privateDisplayLink = nil;
    if (kCVReturnSuccess != CVDisplayLinkCreateWithCGDisplay(CVDisplayLinkGetCurrentCGDisplay(dl), &privateDisplayLink) || !privateDisplayLink)
    {
        NSLog(@"Couldn't create display link for dispatch");
        return;
    }

    CVDisplayLinkSetOutputCallback(privateDisplayLink, DispatchDisplayLinkOneshotCallback, (void*)CFBridgingRetain([block copy]));
    CVDisplayLinkStart(privateDisplayLink);
}

static CVReturn DispatchDisplayLinkOneshotCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
{
    dispatch_block_t block = (dispatch_block_t)CFBridgingRelease(displayLinkContext);
    block();
    CVDisplayLinkStop(displayLink);
    CVDisplayLinkSetOutputCallback(displayLink, NULL, NULL);
    CVDisplayLinkRelease(displayLink);
    return kCVReturnSuccess;
}
CVDisplayLinkRef dl = nil;
if (kCVReturnSuccess != CVDisplayLinkCreateWithActiveCGDisplays(&dl))
{
    NSLog(@"Problem");
}

MYDisplayLinkDispatcher* dld = [[MYDisplayLinkDispatcher alloc] initWithDisplayLink: dl];

for (NSUInteger i = 0; i < 100; i++)
{
    [dld performBlock:^{
        NSLog(@"Whee! Hello from the display link thread! i: %@", @(i));
    }];
}
我确实注意到,根据经验,使用这种方法排队的块的最终执行顺序没有得到维护,因此如果这对您很重要,您可能会希望采用不同的方法,但是如果您只想“在显示链接回调上调用此块”,那么应该这样做

另外,FWIW,从技术上讲,这种方法并不是在你传递给它的确切的
CVDisplayLink
的回调上执行,而是在为显示查询该回调,然后创建一个新的“一次性”
CVDisplayLink
,因此如果你需要强有力的保证,你需要使用确切的
CVDisplayLink
回调,同样,您需要在这周围添加一些额外的机器

-performSelector:onThread:withObject:waituntldone:
是基于runloop的,而且
CVDisplayLink
线程似乎没有runloop(它们有一些东西,但看起来不像
CFRunLoop
)编辑:显然这毕竟是可行的。不知道这是怎么回事,但这是一个选择

编辑:好的,我忍不住。下面是另一个示例,它维护顺序并使用您在初始化时传递给它的特定
CVDisplayLink
。如果您有一个也需要被调用的“主”回调,那么您必须在初始化时将其(及其上下文)传入(因为一旦设置了
CVDisplayLink
,就没有API可以从现有回调中提取,我们需要设置一个回调来服务队列。)

然后要使用它,您可以执行以下操作:

static CVReturn DispatchDisplayLinkOneshotCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext);

void dispatch_async_displaylink(CVDisplayLinkRef dl, dispatch_block_t block)
{
    if (!block || !dl)
        return;

    CVDisplayLinkRef privateDisplayLink = nil;
    if (kCVReturnSuccess != CVDisplayLinkCreateWithCGDisplay(CVDisplayLinkGetCurrentCGDisplay(dl), &privateDisplayLink) || !privateDisplayLink)
    {
        NSLog(@"Couldn't create display link for dispatch");
        return;
    }

    CVDisplayLinkSetOutputCallback(privateDisplayLink, DispatchDisplayLinkOneshotCallback, (void*)CFBridgingRetain([block copy]));
    CVDisplayLinkStart(privateDisplayLink);
}

static CVReturn DispatchDisplayLinkOneshotCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
{
    dispatch_block_t block = (dispatch_block_t)CFBridgingRelease(displayLinkContext);
    block();
    CVDisplayLinkStop(displayLink);
    CVDisplayLinkSetOutputCallback(displayLink, NULL, NULL);
    CVDisplayLinkRelease(displayLink);
    return kCVReturnSuccess;
}
CVDisplayLinkRef dl = nil;
if (kCVReturnSuccess != CVDisplayLinkCreateWithActiveCGDisplays(&dl))
{
    NSLog(@"Problem");
}

MYDisplayLinkDispatcher* dld = [[MYDisplayLinkDispatcher alloc] initWithDisplayLink: dl];

for (NSUInteger i = 0; i < 100; i++)
{
    [dld performBlock:^{
        NSLog(@"Whee! Hello from the display link thread! i: %@", @(i));
    }];
}
CVDisplayLinkRef dl=nil;
if(kCVReturnSuccess!=CVDisplayLinkCreateWithActiveCGDisplays(&dl))
{
NSLog(“问题”);
}
MYDisplayLinkDispatcher*dld=[[MYDisplayLinkDispatcher alloc]initWithDisplayLink:dl];
对于(整数i=0;i<100;i++)
{
[dld性能锁:^{
NSLog(@“Whee!你好,来自显示链接线程!i:%@,@(i));
}];
}

感谢您深入了解这一点!我很好奇为什么你说CVDisplayLink没有运行循环。我最后尝试了performSelector:。。。方法如果我在回调中放置断点,它似乎正在CVDisplayLinkThread上执行,nsrunlop运行模式:。。。出现在堆栈的回溯跟踪中。我错过什么了吗?哇!那么,我想我错了。我在回调的回溯中没有看到任何“常见的嫌疑犯”,所以我假设没有运行循环。可能runloop是按需创建的,或者从属于CVDisplayLink线程主例程。什么都管用,嗯?