Automatic ofTexture release throwing a sigabrt unpredictably

Been seeing some really strange issues where a program that is dynamically loading images to texture will run fine for hours but then hit a sigabrt on this one line in ofTexture.

It is terribly unpredictable in that it can happen after 20minutes of the installation being up, or 12 hours later. Doesn’t seem effected by whether people use the installation or not, doesn’t add stress. The application sits at like 90mb of ram, runs at 7% cpu and is just continuously loading and releasing 612x612px images that it has downloaded in a sort of iamge conveyor belt

I’m thinking threading between the image downloading and texture release could be to blame…I’m not explicitly calling for texture release in my code…has anyone seen similar errors before?

  
static void release(GLuint id){  
	// try to free up the texture memory so we don't reallocate  
	// [http://www.opengl.org/documentation/specs/man-pages/hardcopy/GL/html/gl/deletetextures.html](http://www.opengl.org/documentation/specs/man-pages/hardcopy/GL/html/gl/deletetextures.html)  
	if (id != 0){  
		if(getTexturesIndex().find(id)!=getTexturesIndex().end()){  
			getTexturesIndex()[id]--;  
			if(getTexturesIndex()[id]==0){  
				glDeleteTextures(1, (GLuint *)&id);  //this line inconsistently throws a sigabrt   
				getTexturesIndex().erase(id);  
			}  
		}else{  
			ofLog(OF_LOG_ERROR, "trying to delete a non indexed texture, something weird is happening. Deleting anyway");  
			glDeleteTextures(1, (GLuint *)&id);  
		}  
	}  
}  

I’m getting the same error but consistly when images are referenced from an object in a vector/deque, and the deque is popped in a thread. I wasn’t aware the ofImage was released just because the object referencing it in the vector is erased. Did you get any where with this?

@laserpilot I’ve run into this problem before and it really stressed me out for a while. After spending hours digging into how oF handles textures, I realized I did something stupid with a pointer or dynamically allocated array which overwrote some memory it wasn’t supposed to. Its really hard to say without looking at the affected code, but it might help to have a fresh pair of eyes.

@borg oF handles texture references similarly to a shared pointer. If nothing is referencing it anymore it will be deallocated from the graphics memory. OpenGL is also not thread safe, so doing anything with openGL calls in a thread is potentially dangerous. ofImage by default uses a gl texture, so this may be the culprit.

@Tim: Thanks. Super useful. So say I want to do something fairly common, i.e. to have a vector of ofImages I can add to and send to a separate thread to process away on, how would I do that? I got some isNotAllocated warnings when not passing them by reference, but the real issue is when I run some ofImage function like resize in the threadFuction (even when locked) I get the above error. After all, image processing seems to be one of the prime reasons for using threads.

borg,

can you post your code? as long as your ofImage object are not using a texture, you should be fine using them in a thread.

0072 OSX

testApp.h

  
class testApp : public ofBaseApp{  
  
	public:  
	//..//  
        ImgThread thread;  
		  
};  
  

testApp.cpp

  
  
//--------------------------------------------------------------  
  
void testApp::draw(){  
    for(int i=0;i<thread.imgSharedRefs.size();i++){  
        if(!thread.imgSharedRefs[i]->isAllocated()){  
            ofLog()<<"imgSharedRefs "<<i <<" not allocated"<<endl;  
        }else{  
            thread.imgSharedRefs[i]->draw(i*20,0);  
        }  
    }  
}  
  
  
void testApp::keyReleased(int key){  
    if(key ==' '){  
          
          
        ofImageRef imgRef(new ofImage());  
        imgRef->loadImage("isthislove1.png");  
          
         
        thread.imgSharedRefs.push_back(imgRef);  
          
          
        ofImage img;  
        img.loadImage("isthislove1.png");  
        thread.imgs.push_back(img);  
          
          
        ofImage * imgPointer = new ofImage();  
        imgPointer->loadImage("isthislove1.png");  
        thread.imgPointers.push_back(imgPointer);  
  
        ofLog()<<"thread is running."<< thread.isThreadRunning()<<" Size "<<thread.imgs.size()<<endl;  
  
    }  
      
    if(key =='e'){  
        thread.empty();  
    }  
    if(key =='s'){  
        if(thread.isThreadRunning()){  
            thread.stopThread();  
        }else{  
            thread.startThread(true,true);  
        }  
    }  
      
  
  
}  

ImgThread.h

  
  
#ifndef _ImgThread  
#define _ImgThread  
  
#include "ofMain.h"  
  
  
typedef ofPtr <ofImage> ofImageRef;  
  
class ImgThread : public ofThread {  
	  
  public:  
	  
	ImgThread();  
    ~ImgThread();  
      
    void empty();  
      
    //testing with different containers to test shared scope in threads  
    vector<ofImage> imgs;  
    vector<ofImage *> imgPointers;  
    vector<ofImageRef> imgSharedRefs;  
	  
    void threadedFunction();  
	  
};  
      
      
      
#endif  
  

ImgThread.h

  
  
#include "ImgThread.h"  
ImgThread::ImgThread(){  
      
}  
  
void ImgThread::empty(){  
   // imgs.erase(imgs.begin(),imgs.end());  
    lock();  
    imgs.clear();  
    
    //I realize this does not nullify the pointers  
    imgPointers.clear();  
  
      
    //and this prob doesn't reset the shared pointers right?  
    imgSharedRefs.clear();  
  
      
    ofLog()<<"imgs.size() "<<imgs.size()<<" imgPointers.size() "<<imgPointers.size()<<" imgSharedRefs.size() "<<imgSharedRefs.size()<<endl;  
    unlock();  
}  
  
ImgThread::~ImgThread(){  
     empty();  
  
}  
//------------------------------------------------------------------  
void ImgThread::threadedFunction() {  
    while(isThreadRunning()) {  
        lock();  
        for(int i=0;i<imgs.size();i++){  
            if(!imgs[i].isAllocated()){  
                    ofLog()<<"imgs "<<i <<" not allocated"<<endl;  
            }else{  
                //crashes  
                imgs[i].resize(i*20,90);  
            }  
        }  
          
        for(int i=0;i<imgPointers.size();i++){  
            if(!imgPointers[i]->isAllocated()){  
                ofLog()<<"imgPointers "<<i <<" not allocated"<<endl;  
            }else{  
                //crashes  
               // imgPointers[i]->resize(i*20,90);  
            }  
        }  
  
          
        for(int i=0;i<imgSharedRefs.size();i++){  
            if(!imgSharedRefs[i]->isAllocated()){  
                ofLog()<<"imgSharedRefs "<<i <<" not allocated"<<endl;  
            }else{  
                //crashes  
               // imgSharedRefs[i]->resize(i*20,90);  
            }  
        }  
        unlock();  
          
    }  
	  
}  
  

ImgThread.zip

borg, a couple of things I can see:

In testApp.cpp, you need to call img.setUseTexture(false); before you call loadImage(). As I said before, openGL is not thread safe, and when you call ofImage::resize() on an ofImage object which has a texture attached, it tries to re-allocate the texture inside of a separate thread, which will fail.

Aside from that, stl containers like vector are also not thread safe. Even though you are locking your thread prior to accessing the image vectors, you still may end up accessing that memory outside the thread because you’re directly accessing the vector from the main thread in your keyReleased function without locking the thread there.

If you want to use the producer-consumer pattern with a thread and stl containers, you need to explicitly handle mutex locks whenever you access the shared container. Take a look at how I’ve done this with the ofxVideoRecorder thread. I have a function to add a frame which handles the locking for me. https://github.com/timscaffidi/ofxVideoRecorder/blob/master/src/ofxVideoRecorder.h