views:

1606

answers:

4

I'm drawing offscreen to a CGContext created using CGBitmapContextCreate, then later generating a CGImage from it with CGBitmapContextCreateImage and drawing that onto my view in drawRect (I'm also drawing some other stuff on top of that - this is an exercise in isolating different levels of variability and complexity).

This all works fine when it's all running on the main thread. However one of the motivations for splitting this out this way was so that the offscreen part could be run on a background thread (which I had thought should be ok since it's not rendering to an onscreen context).

However, when I do this the resulting image is empty! I've checked over the code, and placed judicious NSLog's to verify that everything is happening in the right order.

My next step is to boil this down to the simplest code that reproduces the issue (or find some silly thing I'm missing and fix it) - at which point I'd have some code to post here if necessary. But I first wanted to check here that I'm not going down the wrong path with this. I couldn't find anything in my travels around the googlesphere that sheds light either way - but a friend did mention that he ran into a similar issue while trying to resize images in a background thread - suggesting there may be some general limitation here.

[edit]

Thanks for the responses so far. If nothing else they have told me that at least I'm not alone in not having an answer for this - which was part of what I wanted to find out. At this point I'm going to put the extra work into getting the simplest possible example and may come back with some code or more information. In the meantime keep any ideas coming :-)

One point to bring up: A couple of people have used the term thread safety with respect to APIs. It should be noted that there are two types of thread safety in this context:

  1. Threadability of the API itself - ie can it be used at all from more than one thread (global state and other re-entrancy issues such as C's strtok are common reasons that an API might not be thread safe too).
  2. Atomicity of individual operations - can multiple threads interact with the same objects and resources through API without application level locking?

I suspect that mention so far has been of the first type, but would appreciate if you could clarify.

[edit2 - solved!]

Ok, I got it all working. Executive summary is that the problem was with me, rather than bitmap contexts themselves.

In my background thread, just before I drew into the bitmap context, I was doing some preparation on some other objects. It turns out that, indirectly, the calls to those other objects where leading to setNeedsDisplay being called on some views! By separating the part that did that out to the main thread it now all works perfectly.

So for anyone who hits this question wondering if they can draw to a bitmap context on a background thread, the answer is you can (with the caveats that have been presented here and in the answers).

Thanks all

A: 

Not all APIs are thread-safe. Some require locking or require that they be run on the main thread. You may want to scour the documentation. I believe there is a page that summarizes which parts of the SDK are thread-safe and which aren't.

Kailoa Kadano
Thanks Kailoa. I appreciate the response, but this is pretty much where I started from. I was hoping for more specifics since my "scouring the documention" hasn't pulled up anything definitive yet.
Phil Nash
+1  A: 

What you're doing should work if you're working with the CGContextRef in one and only one thread. I've done this before with 8 cores working on 8 different parts of an image and then compositing the different resultant CGImageRefs together and drawing them onscreen.

Lyndsey Ferguson
Thanks. I didn't mention it in my question, but did add the iPhone tag, which may or may not be significant here (as Roger Nolan also alluded to in his answer)
Phil Nash
+1  A: 

Apple don't say anything about thread safety on iPhone but Cocoa (as opposed to UIKit) is generally thread safe for drawing. As they share a lot of drawing code, I would assume drawing on iPhone is threadsafe.

That said, your experience would imply there are problems. Could it be that you are using your image before it is rendered?

Roger Nolan
No. At the end of my thread method I set a call to another method on the main thread, which in turn calls setNeedsDisplay. Only at that point does the image get generated out of the bitmap context and used to draw to the view
Phil Nash
+1  A: 

Just a guess, but if you are trying to call setNeedsDisplay from another thread, you need to call it via performSelectorOnMainThread instead.

dendryte
Thanks. But I am calling it from the main thread. The only thing I'm doing on the other thread is drawing to the bitmap context
Phil Nash
I'm marking yours as accepted because it turned out to be closest to the cause - even if it didn't lead me to it directly :-)
Phil Nash