thread safe ?

Magick++ is an object-oriented C++ interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning Magick++.
Post Reply
blowzy
Posts: 8
Joined: 2011-12-20T12:04:44-07:00
Authentication code: 8675308

thread safe ?

Post by blowzy »

ImageMagick 6.7.3-4 2011-11-29
FREEBSD 8.2-RELEASE
--------
Is IM really thread safe? On one thread that read and process picture is all going ok! but when its two or more threads, program crashed with SEGFAULT. Every thread read from disk NOT the same image as other thread, but (i think) at the same time :)

Code that I using now in every thread for testing(now only make "img" object from disk image, and its still crashed:

Code: Select all

		try 
		{ 	
			{
			std::cout << "read:" <<  picturepath << std::endl;			
			Magick::Image::Image img( picturepath ); 
			std::cout << "readed:" <<  picturepath << std::endl;	
			}
			return 1;
		}
		catch( Magick::Exception &error )
		{
			std::cout << "Caught exception: " << error.what() << std::endl; 
			return 0;
		}
Output something like this:
...skipped...
readed:./content/s2/p1/6/o/4.jpg
read:./content/s2/p1/4/o/9.jpg
read:./content/s2/p1/6/o/5.jpg
readed:./content/s2/p1/4/o/9.jpg
readed:./content/s2/p1/6/o/5.jpg
read:./content/s2/p1/5/o/11.jpg
read:./content/s2/p1/6/o/6.jpg
Segmentation fault (core dumped)
and time to time its not crashed but eat 100% of cpu and IM threads hangs.

what its can be?


ps. Happy New Year, Magick!
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: thread safe ?

Post by magick »

ImageMagick is thread safe, we perform thousands of tests before a release with and without valgrind. However, the OpenMP committee has not defined the behavior of mixing OpenMP with other threading models such as Posix threads. It seems Posix threads and OpenMP coexists peacefully under CentOS / Redhat / Fedora but we have not tested it under FreeBSD. First, set the MAGICK_THREAD_LIMIT environment variable to 1. If that does not help, build ImageMagick without OpenMP support. Add --disable-openmp to your configure script command line, make, and install. Does your threaded application work now? If not, try downloading the latest release of ImageMagick, 6.7.4-4. Does that help? If not, post a URL to a minimum set of code we can download and build to reproduce the problem. We'll see if we can reproduce the problem in our environment. If not, we'll try to find a FreeBSD system to determine why the concurrent threads fail.
blowzy
Posts: 8
Joined: 2011-12-20T12:04:44-07:00
Authentication code: 8675308

Re: thread safe ?

Post by blowzy »

Thanks for the answer.
Already do some steps, will continue tomorrow.
1) Seems that OpenMP disabled by default on FreeBSD config (i install IM from ports) and "make config" show that OpenMP is disables. Hmmm... seems that by default its compiled --without-threads - maybe its the reason?? is IM thread-safe when compiled --without-threads?
2) setenv MAGICK_THREAD_LIMIT 1 - does not help.


=======================
Before I read your answer, I am already make some tests and have additional information:
after testing, still seems like the bug in the imagemagick, because I can read image content myself from the file on multy-thread application and than create BLOB structure from it and its ok.

Code: Select all

Magick::Blob blob( ((void*) str.c_str() ), size );
but

Code: Select all

Magick::Image::Image img( blob );	
still crashed with Segmentation fault time to time.

ps. another little inconvenience is that ImageMagick violates my SIGINT (ctrl+c) handler (i think puts there own SIG_IGNore) and every time after using ImageMagick I need to return my handler.

Code: Select all

signal(SIGINT, Signal_Handler);
can this cause?..

thanks. wasn't expecting that you will answer so quickly! thanks!!
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: thread safe ?

Post by magick »

Here is one of our thread unit tests. Try it under FreeBSD. Does it work / fail for you?

Compile with
  • g++ `Magick++-config --cxxflags --cppflags` -O2 -Wall -o thread++ thread++.cpp `Magick++-config --ldflags --libs

Code: Select all

#include <Magick++.h>
#include <iostream>
#include <list>

using namespace std;

using namespace Magick;

Image source;

void *testthread(void * data)
{
  char num=static_cast<char>(reinterpret_cast<long>(data));

  // Wait a bit, so all threads have a chance to start
  sleep(1);
  for (int i=0; i < 5; ++i) {
    
    // Make thread-private copy of source image.
    Image image(source);
    
    // Here, the image should be really copied.
    image.border(Geometry((rand()%10)+10,(rand()%10)+10));
    cout << "  Size: " << image.columns() << 'x' <<image.rows() << endl;

    // Each thread has its own Blob to write to.
    Blob blob2;
    
    // And write to private blob.
    image.write( &blob2 );
    image.write( "test.jpg" );
    cout << "Thread " << num << ": Blob-Length " << blob2.length() << endl;
  }
  return NULL;
}

int main( int /*argc*/, char ** argv)
{
  // Initialize ImageMagick
  InitializeMagick(*argv);

  try {
    {
      // Read test image, just to have some pixels available    
      Image image("logo.jpg");
      Blob blob;
      image.write( &blob );
      cout << "Size: " << image.columns() << 'x' <<image.rows() << " / JPEG Blob-Length: " << blob.length() << endl;

      // copy to global image.
      source=image;
      // Make source smaller, so the threads spend less time scaling and more time crashing.
      source.scale(Geometry(150,150));
    }
  } catch( Exception &error_ ) {
    cout << "Caught Exception: " << error_.what() << endl;
    return 1;
  } catch( exception &error_ ) {
    cout << "Caught exception: " << error_.what() << endl;
    return 1;
  }

  // Now start a bunch of threads.
  list<pthread_t> threads;

  pthread_attr_t attr;
  pthread_attr_init(&attr);
  for (char i='A'; i<='Z'; ++i) {
    pthread_t thread;
    pthread_create(&thread,&attr,testthread,reinterpret_cast<void *>
      (static_cast<long>(i)));
    threads.push_back(thread);
  }

  // Wait for all threads to terminate.
  for (list<pthread_t>::iterator it=threads.begin(); it!=threads.end(); ++it) {
    void * result;
    pthread_join(*it,&result);
  }
  return 0;
}
Post Reply