Page 1 of 1

Loading images asynchronously

Posted: 2014-03-07T06:05:24-07:00
by sswiercy
I'm using the MagickWand C API (6.8.7-7-Q16-x86-dll) and I encounter errors from time to time when loading multiple images concurrently. Consider the following piece of code:

Code: Select all

void loadImage(const std::string& filename) {
	
	std::ifstream file(filename,std::ifstream::binary);
	std::ostringstream blob;
	blob << file.rdbuf();

	MagickWand* wand = NewMagickWand();
	MagickReadImageBlob(wand,blob.str().data(),blob.str().size());

	ExceptionType type;
	const char* msg = MagickGetException(wand,&type);

	if (type != UndefinedException) {
		std::cout << "error: " << msg << std::endl;
	} else {
		std::cout << "successful" << std::endl;
	}

	DestroyMagickWand(wand);
}

void runner(boost::asio::io_service& service) {
	service.run();
}

int main() {

	boost::asio::io_service service;
	boost::asio::io_service::work work(service);
	service.post(boost::bind(&loadImage,std::string("test1.jpg")));
	service.post(boost::bind(&loadImage,std::string("test2.jpg")));
	boost::thread t1(boost::bind(&runner,boost::ref(service)));
	boost::thread t2(boost::bind(&runner,boost::ref(service)));
	std::cin.ignore();
	
	return EXIT_SUCCESS;
}
This code is not fully runnable but should give you an idea about how to trigger this error. It simply starts two threads which load two images concurrently. Sometimes, loading one of the images fails. The error message returned by MagickGetException then is:

no decode delegate for this image format `' @ error/blob.c/BlobToImage/358

Unfortunately, this error is hard to trigger. Often it occurs only on the first run of the application, but runs fine when executing it again. What I realized is, that this error only happens when the first images are loaded, so I could imagine that the error is due to some kind of global library initialization. Do I need to call a function for that? I tried to call MagickWandGenesis at the beginning of main, but that didn't fix it.

Thank you for any ideas about what I'm doing wrong. For now I'm using a workaround by avoiding to load images concurrently.

Re: Loading images asynchronously

Posted: 2014-03-07T07:09:20-07:00
by magick
Use MagickWandGenesis() before you call any other MagickWand API methods. Does that fix the problem. It should not be necessary, but perhaps that will resolve the race condition. If not, post a code segment we can download and build so we can reproduce the problem. If we can reproduce the problem, we'll have a patch available to fix the problem within a few days.

Re: Loading images asynchronously

Posted: 2014-03-07T07:46:58-07:00
by sswiercy
Thank you for your answer. MagickWandGenesis did not help for me. Here is a code snippet that should reproduce the error. Note that you might have to run it several times until the error occurs.

Code: Select all

#include <string>
#include <fstream>
#include <sstream>

#include <boost/thread.hpp>
#include <wand/MagickWand.h>


void load(const std::string& filename) {
   
   std::ifstream file(filename,std::ifstream::binary);
   std::ostringstream blob;
   blob << file.rdbuf();

   MagickWand* wand = NewMagickWand();
   MagickReadImageBlob(wand,blob.str().data(),blob.str().size());

   ExceptionType type;
   const char* msg = MagickGetException(wand,&type);

   if (type != UndefinedException) {
      std::cout << "error: " << msg << std::endl;
   } else {
      std::cout << "successful" << std::endl;
   }

   DestroyMagickWand(wand);
}

int main() {

	MagickWandGenesis();
	boost::thread t1(boost::bind(&load,std::string("test1.jpg")));
	boost::thread t2(boost::bind(&load,std::string("test2.jpg")));
	std::cin.ignore();
   
	return EXIT_SUCCESS;
}
Note that the Boost library is required to be installed. I think any two test images should suffice to reproduce the error.

Re: Loading images asynchronously

Posted: 2014-03-07T09:51:56-07:00
by magick
We can reproduce the problem you posted and have a patch in ImageMagick 6.8.8-8 Beta, available in a week or two. Thanks.