• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Synchronizing Thread Execution
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Synchronizing Thread Execution


  • Subject: Re: Synchronizing Thread Execution
  • From: Antonio Nunes <email@hidden>
  • Date: Mon, 4 Dec 2006 14:14:54 +0000

On 3 Dec 2006, at 23:23, Chris Suter wrote:

I have instances of a class that can be called from two threads at "the same time". For one method I need to ensure it is only executed by one thread at a time, regardless of which instance of the class is being called, and from which thread. Am I correct that using "@synchronized(NSStringFromSelector(_cmd))" would provide precisely this guarantee?

Yes, it would seem so.

That's what I thought too, but after some experimentation it doesn't seem to work, or I am misunderstanding what it means. Using the above expression it seems the objects are being modified from somewhere else while we are in the critical region. Using @synchronized(self) this doesn't happen. But this last expression still doesn't provide enough protection:


The issue is that I have a possibly large number of objects which all reference the same PDFDocument in a cache. A background thread is spun from the main thread calling each object in turn to convert the cache into something derived from the PDFDocument. This serialized operation in itself is fine. The complication is that when the main thread calls a document window's drawRect method, the drawing code will call the same objects to draw, and if the cache has not been converted yet for an object that will trigger the conversion routine which accesses the PDFDocument from the main thread, re-entering the PDFDocument. This PDFDocument doesn't like and it usually results in severe errors. Much of this is prevented by wrapping @synchronized (self) around the critical region. At least then the two threads cannot simultaneously access the same object. But this is not enough, since several objects may reference the same PDFDocument and hence it may still be accessed from two threads simultaneously. I had hoped that using @synchronized(NSStringFromSelector(_cmd)) would further prevent this by only allowing one thread at a time access to this method. Yet, I ended up getting more errors; in fact things started going consistently wrong now, whereas with @synchronized(self) things were mostly OK (at least on single processor/core machines, on multiple processor/core machines the errors are more frequent).

After posting this question last night, I thought I'd try to make the conversion triggering thread block while the main thread is drawing. That *should* avoid the issue of the PDFDocument being re-entered. So I tried the following:

- (NSLock *)blockConversion; <=instance variable of the NSView subclass

- (void)drawRect:(NSRect)rect {
	[blockConversion lock];

	// Do some drawing stuff

	[blockConversion unlock];
}


Background thread spun from the main thread after importing a PDF document:


- (void)convertPDFSourceObjectCaches:(NSArray *)objects
{
	…

	while ((sourceObject = [e nextObject]) && !_isSaving && !_isClosing) {
		…

		if ([sourceObject owner]) {
			[[layoutView blockConversion] lock];
			[sourceObject convertCacheToPDFDoc];
			[[layoutView blockConversion] unlock];
		}
	}

	…
}

The idea is that drawRect will draw if convertPDFSourceObjectCaches hasn't triggered a cache conversion, and convertPDFSourceObjectCaches will convert an object's cache only if no drawing is taking place. But this turns out to be susceptible to (I think) racing conditions since the both threads block when running this setup, or at any rate, the UI freezes.

So I changed drawRect to this:

- (void)drawRect:(NSRect)rect {
	[blockConversion tryLock];
	…

This avoids the blocking and the background thread will only execute when no drawing is taking place. Yet there is still a chance that when drawRect is called the background thread has not yet finished an ongoing conversion so we might still have a problem.

How then to solve this? Would I be better off with a condition lock? And how would I implement that?

-António

-----------------------------------------
Forgiveness is the perfume
that the trampled flower casts
upon the heel that crushes it.
-----------------------------------------



_______________________________________________

Cocoa-dev mailing list (email@hidden)

Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


  • Follow-Ups:
    • Re: Synchronizing Thread Execution
      • From: leenoori <email@hidden>
    • Re: Synchronizing Thread Execution
      • From: Scott Ribe <email@hidden>
References: 
 >Synchronizing Thread Execution (From: Antonio Nunes <email@hidden>)
 >Re: Synchronizing Thread Execution (From: Chris Suter <email@hidden>)

  • Prev by Date: Re: Bindings Question
  • Next by Date: Re: AdditionalEventParamDescriptor odoc
  • Previous by thread: Re: Synchronizing Thread Execution
  • Next by thread: Re: Synchronizing Thread Execution
  • Index(es):
    • Date
    • Thread