Re: passing complex objects between threads
Re: passing complex objects between threads
- Subject: Re: passing complex objects between threads
- From: Eric Hermanson <email@hidden>
- Date: Fri, 24 Apr 2009 21:41:02 -0400
FYI, I wrote a blocking queue that is very similar to Java's
BlockingQueue. I haven't tested it very much yet, so no guarantees to
this code...
enum _Lock {
EMPTY,
NOT_EMPTY
};
@implementation BlockingQueue
- (id)initWithCapacity:(NSUInteger)capacity
{
if((self = [super init]) != nil) {
_conditionLock = [[NSConditionLock alloc] initWithCondition:EMPTY];
_array = [[NSMutableArray alloc] initWithCapacity:capacity];
_capacity = capacity;
}
return self;
}
- (void)dealloc
{
[_conditionLock release];
[_array release];
[super dealloc];
}
- (void)performUnlock
{
[_conditionLock unlockWithCondition:([_array count] > 0) ?
NOT_EMPTY : EMPTY];
}
- (id)take
{
[_conditionLock lockWhenCondition:NOT_EMPTY];
id object = [_array objectAtIndex:0];
[_array removeObjectAtIndex:0];
[self performUnlock];
return object;
}
- (id)poll
{
return [self pollBeforeDate:[NSDate date]];
}
- (id)pollBeforeDate:(NSDate *)limitDate
{
id object;
BOOL locked = [_conditionLock lockWhenCondition:NOT_EMPTY
beforeDate:limitDate];
if(locked == YES) {
object = [[[_array objectAtIndex:0] retain] autorelease];
[_array removeObjectAtIndex:0];
[self performUnlock];
}
else {
object = nil;
}
return object;
}
- (BOOL)add:(id)object
{
if(object == nil) {
@throw [NSException exceptionWithReason:@"BlockingQueue add: must
supply non-nil object!" userInfo:nil];
}
BOOL ok;
BOOL locked = [_conditionLock tryLock];
if(locked == YES) {
@try {
if([_array count] < _capacity) {
[_array addObject:object];
ok = YES;
}
else {
@throw [NSException exceptionWithReason:[NSString
stringWithFormat:@"BlockingQueue full: %d", _capacity] userInfo:nil];
}
}
@finally {
[self performUnlock];
}
}
else {
ok = NO;
}
return ok;
}
- (BOOL)offer:(id)object
{
return [self offer:object beforeDate:[NSDate date]];
}
- (BOOL)offer:(id)object beforeDate:(NSDate *)limitDate
{
if(object == nil) {
@throw [NSException exceptionWithReason:@"BlockingQueue add: must
supply non-nil object!" userInfo:nil];
}
BOOL ok;
BOOL locked = [_conditionLock lockBeforeDate:limitDate];
if(locked == YES) {
if([_array count] < _capacity) {
[_array addObject:object];
ok = YES;
[self performUnlock];
}
else {
ok = NO;
}
}
else {
ok = NO;
}
return ok;
}
- (void)put:(id)object
{
if(object == nil) {
@throw [NSException exceptionWithReason:@"BlockingQueue add: must
supply non-nil object!" userInfo:nil];
}
BOOL done = NO;
while(done == NO) {
[_conditionLock lock];
if([_array count] < _capacity) {
[_array addObject:object];
done = YES;
}
[self performUnlock];
}
}
On Apr 24, 2009, at 9:33 PM, Eric Hermanson wrote:
I believe you should use a producer-consumer pattern where the
consumer thread waits on a blocking queue for the incoming object,
and the producer thread passes the fetched object to the blocking
queue after its fetched. There are many examples of producer/
consumer on the web...
- Eric
On Apr 24, 2009, at 9:24 PM, Daniel Child wrote:
I have a Core Data app that imports data via a separate managed
object contexts. Without multithreading, the operation works fine.
But since the import takes over a minute, I want to do the import
in a different thread. The data consists of an archived table of
data with records.
This is my first time attempting to use threads, and the basic
problem I'm having is figuring out the best way to pass the complex
object (the table of records) from one thread to another. Since
there are something like 50,000 records, deep-copying would be ugly.
I thought of three workarounds.
1. Unarchive the table to be parsed while in the second thread so
you have the original, not a copy. Should work, but it's kind of
skirting the issue.
2. Create a global variable and copy the table into it . I tried
this, but the table's records ivar is still not deep-copied.
3. The thread is called by the app controller with thread's owner
set to the app controller itself. i.e. (void) doImportThread: (id)
owner [== self / appController]. Theoretically, I should be able to
cache the table as appController ivar and access it from within the
thread as [owner tableToParse]. I tried this too, and just as with
the global variable approach, the actual records are not available
within the second thread, only the simple ivars.
This must be a common issue with multithreading. Is there an
elegant way to get access to deeper layers of a complex object from
within another thread? i.e. a way to make 2) or 3) above work?
Thanks.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please 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
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please 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
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please 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