NSCondition


Dave
 

Hi All,

I’ve almost got my threaded Consumer/Producer Working using NSThread and friends. However, under certain circumstances, I’m getting objects “stuck” on the queue and the Consumer thread not firing. If I cause it to send another object, then I see the missing object (since it tries to process the whole array each time the ConsumerTask Fires and the New Object.

Here is some code on what I am doing.

Producer Task:

-(void) addObjectToProcessQueue:(id) theNewObject
{
LTWQueueTaskObjectStatusType myStatus;
id myHeadObject;

if (theNewObject == nil)
return;

//**
//** Lock and Get Status
//**
[self.pQueueTaskConsumerTaskWakeUpCondition lock];
myStatus = [self checkObjectIsValid:theNewObject];

//**
//** Check Status
//**
switch (myStatus)
{
case kLTWQueueTaskObjectStatusOverwriteHead:
myHeadObject = [self.pQueueTaskProcessingQueue queueGetHead];
[myHeadObject setDataFrom:theNewObject]; //Just copies properties
[self.pQueueTaskConsumerTaskWakeUpCondition signal];
break;

case kLTWQueueTaskObjectStatusAddToTail:
[self.pQueueTaskProcessingQueue queuePutTail:theNewObject];
[self.pQueueTaskConsumerTaskWakeUpCondition signal];
break;

case kLTWQueueTaskObjectStatusAddToHead:
[self.pQueueTaskProcessingQueue queuePutHead:theNewObject];
[self.pQueueTaskConsumerTaskWakeUpCondition signal];
break;

default:
break;
}

[self.pQueueTaskConsumerTaskWakeUpCondition unlock];
}

---------------------------------------

Consumer Task:

-(void) consumerTask
{
while (YES)
{
[self.pQueueTaskConsumerTaskWakeUpCondition lock];
[self.pQueueTaskConsumerTaskWakeUpCondition wait];

do
{
self.pQueueTaskLastObjectRemoved = [self.pQueueTaskProcessingQueue queueGetHead];
if (self.pQueueTaskLastObjectRemoved != nil)
[self processObject:self.pQueueTaskLastObjectRemoved];
}
while ([self.pQueueTaskProcessingQueue queueGetCount] != 0);

[self.pQueueTaskConsumerTaskWakeUpCondition unlock];
}
}

pQueueTaskConsumerTaskWakeUpCondition is defined as an NSCondition Class. 

I’m using NSCondition, but having problems, I’m confused over this in the in documentation:

"A boolean predicate is an important part of the semantics of using conditions because of the way signaling works. Signaling a condition does not guarantee that the condition itself is true. There are timing issues involved in signaling that may cause false signals to appear. Using a predicate ensures that these spurious signals do not cause you to perform work before it is safe to do so. The predicate itself is simply a flag or other variable in your code that you test in order to acquire a Boolean result. "
 
In my case, the “boolean predicate” is actually the NSArray that holds the objects to process (or more correctly its [NSArray count] != 0), however under certain circumstances, I’m getting objects “stuck” on the queue and the Consumer thread not firing. If I cause it to send another object, then I see the missing object since it tries to process the whole array each time the ConsumerTask Fire.

Looking at the above example - it actually over-signals, since in the case where the object data is overwritten, it has already signalled when the Object was added, however if I don’t signal here, even more objects get “stuck”.

I can’t help thinking from reading the above documentation that this mechanism is a bit hit-and-miss, I can’t remember any other OS/Kernel where I’ve read something like "There are timing issues involved in signaling that may cause false signals to appear.”, and I’m trying to make sense of what it means, it seems to suggest that there may be more signals then expected, whereas I’m seeing less (I think), so it shouldn’t apply?

Anyone have any ideas on how what could be going wrong and how to debug it, I’d love to hear them!

All the Best
Dave















Join cocoa@apple-dev.groups.io to automatically receive all group messages.