3

On the iPhone, I would like to do some operations on an image in a separate thread. Rather than dealing with semiphores, locking, etc., I'd like to use the 'One Object, One Thread' method of safely writing this concurrent operation. I'm not sure what is the correct way to copy my object into a new thread so that the object is not accessed in the main thread. Do I use the 'copy' method? If so, do I do this before the thread or inside the thread?

     ...
    -(void)someMethod{
        UIImage *myImage;
        [NSThread detachNewThreadSelector:@selector(getRotatedImage:) toTarget:self withObject:myImage];

    }

    -(void)getRotatedImage:(UIImage *)image{
        ...
        ...
        UIImage *copiedImage = [image copy];
        ...
        ...
    }
GingerBreadMane
  • 2,630
  • 1
  • 30
  • 29
  • 1
    As fair warning, you have to be very careful when editing images on another thread. It is very easy to get into trouble calling methods and functions that can only safely be run on the main thread. Also, since the iPhone is single-core, weigh very carefully what gains you get from doing it this way. It may be better to redesign the application interface all together. – Jason Coco Mar 12 '10 at 04:22
  • 1
    This is great point. I knew that user interface elements could only be called from the main thread, but it's actually all UIkit objects which includes UIImage. I will use CGImageRef instead. – GingerBreadMane Mar 12 '10 at 04:53
  • GingerBreadMane: The public `UIImage` methods are actually thread-safe currently, but since that's not in the interface contract, it shouldn't be depended on. (`UIImage` is just a thin wrapper over `CGImageRef`) – rpetrich Mar 12 '10 at 09:48
  • That's good to know, and it explains why I haven't experienced any issues yet calling UIImage in separate threads. But like you said, it shouldn't be depended on. – GingerBreadMane Mar 13 '10 at 20:28

2 Answers2

5

Typically, when implementing something like this, you don't create a single thread per object - instead, when you get something for the object to do, you queue it to be handled by a thread pool.

Depending on the number of objects, one thread per object doesn't scale very far.

kyoryu
  • 12,848
  • 2
  • 29
  • 33
4

The best thing to do is simply to take the object of interest, pass it into the worker thread and not reference it in the main thread once the worker thread has been started.

enter scope
    create object
    pass the object to the processing thread
    start the processing thread
exist scope
// the object is no longer visible/used/referenced

The most important thing to note: if your main thread is not going to share the object with the worker thread, then it doesn't matter if you create the object on the main thread, create it in the worker thread, copy the object first and then start the thread, or start the thread and copy the object... the important thing is that you DO NOT share the object between the two threads. How you do that is irrelevant.

Update:
Per your comment... if your main thread still needs to access the image at the same time that you are processing it in the getRotatedImage worker thread, then you will have to make the copy before you pass it in the worker thread. If you pass the image in the thread and try to copy it inside the thread, then there is no guarantee that the image will remain unchanged before/while you copy it.

Kiril
  • 39,672
  • 31
  • 167
  • 226
  • The image DOES need to be accessed by other methods in the main thread. The secondary, worker thread just needs the image to perform some calculations and then report those calculations. Does what I've done in my original post successfully keep the main thread and secondary thread from sharing the objects? – GingerBreadMane Mar 12 '10 at 04:47
  • @GingerBreadMane I've updated my answer based on your comment. I hope it helps. – Kiril Mar 12 '10 at 05:15
  • @GingerBreadMane To answer your question directly: No, given the information you gave me I don't believe that it's safe to copy the image inside the thread. Do it before you pass it in the thread. – Kiril Mar 12 '10 at 05:22
  • Thanks for clearing this up for me Lirik. Is [myImage copy]; the appropriate method to use? Does this create a new copy of the object in memory? Also, would the following also create a copy of myImage, or not: UIImage *imageToPassToThread = [[UIImage alloc] init]; imageToPassToThread = myImage; – GingerBreadMane Mar 13 '10 at 20:33
  • @GingerBreadMane unfortunately my "expertise" ends with the multithreading concepts. I don't have any experience with the IPhone library, so I can't give you any useful advice on how to properly copy the image... but I hope my answer pointed you in the right direction. – Kiril Mar 14 '10 at 08:49