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
C++ 在第二个线程上加载OpenGL资源_C++_Multithreading_Opengl - Fatal编程技术网

C++ 在第二个线程上加载OpenGL资源

C++ 在第二个线程上加载OpenGL资源,c++,multithreading,opengl,C++,Multithreading,Opengl,我在OpenGL 2.1中使用win32线程。我试图实现的是在背景中加载整个3D场景时,渲染简单的图像,并显示“加载”。它现在可以工作了,但我有一个问题,有时候我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器中获取数据(这到底是怎么发生的?),而忽略那个小盒子,有纹理的话,它只是一个精灵,应该在那里 这种情况在我尝试加载程序的3次中有1次发生。 这是我的线程的外观: WindowsThread::WindowsThread(HGLRC graphicsContext, HDC

我在OpenGL 2.1中使用win32线程。我试图实现的是在背景中加载整个3D场景时,渲染简单的图像,并显示“加载”。它现在可以工作了,但我有一个问题,有时候我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器中获取数据(这到底是怎么发生的?),而忽略那个小盒子,有纹理的话,它只是一个精灵,应该在那里

这种情况在我尝试加载程序的3次中有1次发生。 这是我的线程的外观:

WindowsThread::WindowsThread(HGLRC graphicsContext, HDC deviceContext) :
    graphicsContext_(graphicsContext),
    deviceContext_(deviceContext),
    running_(false),
    task_(0),
    mode_(WT_NORMAL)
{
    handle_ = CreateThread(0, 0,
        (unsigned long (__stdcall *)(void *)) this->staticRun,
        (void*) this, CREATE_SUSPENDED, &id_);

    if (handle_ == 0) {
        LOGE("Unable to create thread.");
        return;
    }

    if (!SetThreadPriority(handle_, THREAD_PRIORITY_NORMAL)) {
        LOGE("Unable to set thread priority for thread.");
        return;
    }
}

WindowsThread::~WindowsThread() {
    finishTask();
    running_ = false;
    WaitForSingleObject(handle_, INFINITE);
    CloseHandle(handle_);
    wglDeleteContext(graphicsContext_);
}

void WindowsThread::start() {
    running_ = true;
    if (!ResumeThread(handle_)) {
        LOGW("Unable to resume thread.");
    }
}

bool WindowsThread::isRunning() {
    return running_;
}

void WindowsThread::setTask(Task* task, Mode mode) {
    finishTask();
    task_ = task;
    mode_ = mode;
}

bool WindowsThread::hasTask() {
    return task_ != 0;
}

void WindowsThread::finishTask() {
    while (task_ != 0) {
        Sleep(1);
    }
}

void WindowsThread::stop() {
    running_ = false;
}

int WindowsThread::staticRun(void* thread) {
    return ((WindowsThread*) thread)->run();
}

int WindowsThread::run() {
    wglMakeCurrent(deviceContext_, graphicsContext_);
    while (running_) {
        if (task_ != 0) {
            task_->run();
            task_ = 0;
        }
        Sleep(10);
    }
    wglMakeCurrent(0, 0);
    return 1;
}
线程管理器:

WindowsThreadManager::WindowsThreadManager(
    System* system, UINT threadPoolSize)
{
    if (threadPoolSize == 0) {
        SYSTEM_INFO info;
        GetSystemInfo(&info);
        threadPoolSize = info.dwNumberOfProcessors;
        if (threadPoolSize == 0) {
            threadPoolSize = 1;
        }
    }
    LOGI("Number of threads used: %d", threadPoolSize);
    masterContext_ = wglGetCurrentContext();
    HDC hdc = wglGetCurrentDC();
    for (UINT i = 0; i < threadPoolSize; i++) {
        HGLRC threadContext = wglCreateContext(hdc);
        wglShareLists(masterContext_, threadContext);
        WindowsThread* thread = new WindowsThread(threadContext, hdc);
        thread->start();
        threads_.push_back(thread);
    }
}

WindowsThreadManager::~WindowsThreadManager() {
    for (UINT i = 0; i < threads_.size(); i++) {
        delete threads_[i];
    }
    for (UINT i = 0; i < tasks_.size(); i++) {
        delete tasks_[i];
    }
}

void WindowsThreadManager::execute(Task* task, Mode mode) {
    WindowsThread::Mode wtMode = WindowsThread::WT_NORMAL;
    if (mode == TM_GRAPHICS_CONTEXT) {
        wtMode = WindowsThread::WT_GRPAHICS_CONTEXT;
    }
    tasks_.push_back(task);
    for (UINT i = 0; i < threads_.size(); i++) {
        if (!threads_[i]->hasTask()) {
            threads_[i]->setTask(task, wtMode);
            return;
        }
    }
    threads_[0]->setTask(task, wtMode);
}

void WindowsThreadManager::joinAll() {
    for (UINT i = 0; i < threads_.size(); i++) {
        if (threads_[i]->hasTask()) {
            threads_[i]->finishTask();
        }
    }
}
WindowsThreadManager::WindowsThreadManager(
系统*系统,UINT线程池大小)
{
if(threadPoolSize==0){
系统信息;
GetSystemInfo(&info);
threadPoolSize=info.dwNumberOfProcessors;
if(threadPoolSize==0){
threadPoolSize=1;
}
}
LOGI(“使用的线程数:%d”,线程池大小);
masterContext_u2;=wglGetCurrentContext();
HDC HDC=wglGetCurrentDC();
对于(UINT i=0;i开始();
螺纹。推回(螺纹);
}
}
WindowsThreadManager::~WindowsThreadManager(){
对于(UINT i=0;ihasTask()){
线程[i]->setTask(任务,wtMode);
返回;
}
}
线程[0]->setTask(任务,wtMode);
}
void WindowsThreadManager::joinAll(){
对于(UINT i=0;ihasTask()){
线程[i]->finishTask();
}
}
}
我在Winodws 8上使用带有最新驱动程序的Nvidia 670GTX。 你知道问题出在哪里吗

[EDIT]我在加载程序线程的末尾添加了glFinish(),现在所有内容都正常加载。我在某个地方看到,OpenGL并没有立即完成它的所有工作,所以我猜是这样的,在它完成它的工作之前,上下文被设置为NULL

它现在可以工作了,但我有一个问题,有时我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器获取数据(这到底是怎么发生的?)

纹理从未初始化的图形内存接收数据,该内存很可能包含以前使用该内存区域的另一个进程的剩余图像。这样的事情可能会发生,如果

a) 驱动程序有一个bug,不能在线程之间同步资源

b) 如果您试图修改纹理,而它绑定到另一个线程中的纹理单元


编辑:您可以(也应该)自己引入适当的同步。只是因为它提高了性能。当纹理当前不忙时,用于在线程之间进行通信。理想情况下,您可以使用两个或多个纹理,以循环方式进行更新。

请注意,opengl和线程通常不会同时使用。是的,我对此非常感兴趣。事实上,我之前已经实现了两个上下文,一个是我渲染的,另一个是我加载了资源,当加载资源时,我只是将该上下文作为主上下文,同时删除最后一个主上下文。这没有任何问题。@B:OpenGL和多线程都可以完成,但要正确操作并不简单。@datenwolf是的,但如果我理解这篇文章,他是在线程中创建纹理(或者他在线程中渲染某些内容?)。因为这是随机发生的(三次尝试中有一次),这表明他没有做对,并创造了某种竞赛条件。@Bааћ:是的,这很可能是竞赛条件,但他在共享纹理空间中使用了上下文。这意味着OpenGL实现的负担是在纹理管理中引入正确的同步点。最糟糕的情况应该是丢弃的帧,而不是导致从未初始化内存中获取数据的竞争条件。如果我理解正确,您建议只使用一个上下文,并在我使用它的地方同步所有部分,以便不存在任何竞争条件?或者使用多个上下文,但仍在同步我自己,这样opengl驱动程序就不必了?@SMGhost:不!使用两个上下文(不要在线程之间玩烫手山芋)。但是使用条件变量,以便更新线程知道何时可以安全地修改纹理的内容。如果尚未使用glTexSubImage2D,也可以使用它。在循环循环中保留2或3个纹理,在绘制之前将纹理更新一个索引。目前没有任何情况下,一旦加载纹理就会被修改,之后,在加载资源后,所有图形操作仅在具有单个上下文的主线程上工作。我尝试实现整个场景加载机制的方式是,加载程序线程加载的内容在加载整个资源之前不会被主线程使用,然后我从这些资源开始渲染。我假设在这种情况下不需要条件变量?:)@啊,好的。我以为你的意图是创造一个视频播放器。在这种情况下,不需要条件变量。