This is TestCounter.m in view mode; [Download] [Up]
/* * Counter: simple counter object that runs in its own thread. */ #import <libc.h> #import <math.h> #import <appkit/Button.h> #import <appkit/Slider.h> #import "Counter.h" #import "ThreadedApp.h" #import "tprintf.h" #define INITIAL_INTERVAL 100 // in milliseconds @interface Counter(CounterPrivate) - (int)incCount; - (void)counter:sender; @end @implementation Counter : Object // number of counters created static int counters; // global variable shared among all Counter instances static volatile int *countp; // lock to synchronize access to countp static CJRConditionLock *inclock; #define STOPPED 0 #define RUNNING 1 #define myrandom() (random()/(double)MAXINT) + initialize { if( self == [Counter class] ){ srandom(0); counters = 1; inclock = [[CJRConditionLock alloc] initWithCondition:0]; tprintf_init(); } return self; } - init { NXScreen *screen; NXRect frame; [super init]; interval = INITIAL_INTERVAL; running = NO; mynum = counters++; lastcount = -1; count = 0; if( [NXApp loadNibSection:"Counter.nib" owner:self] ){ // set window title... title = (char *) malloc( 20*sizeof(char) ); // should be enough... sprintf( title, "Counter %d\n", mynum ); [window setTitle:title]; // move to random location [window getFrame:&frame andScreen:&screen]; frame.size.width = screen->screenBounds.size.width - frame.size.width; frame.size.height = screen->screenBounds.size.height - frame.size.height; frame.origin = screen->screenBounds.origin; frame.origin.x += myrandom()*frame.size.width; frame.origin.y += myrandom()*frame.size.height; [window moveTo:frame.origin.x:frame.origin.y]; [window makeKeyAndOrderFront:self]; // set values [slider setIntValue:interval]; [intervalField setIntValue:interval]; [countField setIntValue:count]; runlock = [[CJRConditionLock alloc] initWithCondition:STOPPED]; // go! [self start:self]; } return self; } - free { if( running ) [self stop:self]; [runlock free]; if(title){ free(title); } return [super free]; } - windowWillClose:sender { [self stop:self]; [NXApp delayedFree:self]; return self; } // "private" methods - dispCount:(int)i { if( i != lastcount+1 ){ tprintf("Counter %d: lost %d message(s)\n", mynum, i-lastcount-1); } [countField setIntValue:i]; lastcount = i; return self; } - (int)incCount // a pretty dumb way to increment a counter, but it sure tests // the callback and lock mechanism... { [inclock lockWhenCondition:0]; count++; countp = &count; [inclock unlockWithCondition:mynum]; return count; } - (void)counter:sender { int i; [runlock lockWhenCondition:RUNNING]; i = count; while( running ){ // update countField under main thread [NXApp callbackTarget:self perform:@selector(dispCount:) with:(id)i]; // increment the counter... [NXApp safeCallbackTarget:self perform:@selector(incCount)]; [inclock lockWhenCondition:mynum]; i = *countp; [inclock unlockWithCondition:0]; if( i != count ){ tprintf("Counter %d: count mismatch! ret=%d; count=%d\n", mynum, i, count ); } if( interval > 0 ) [NXApp sleepCurrentThread:interval]; } [runlock unlockWithCondition:STOPPED]; } // Actions... - start:sender { if( !running ){ [runlock lock]; [NXApp detachNewThreadSelector:@selector(counter:) toTarget:self withObject:self]; running = YES; [runlock unlockWithCondition:RUNNING]; } return self; } - stop:sender { if( running ){ running = NO; // wait for thread to finish [runlock lockWhenCondition:STOPPED]; [runlock unlock]; } return self; } - startOrStop:sender { if( [sender state] == 0 ){ [self start:sender]; } else { [self stop:sender]; } return self; } - reset:sender { count = 0; return self; } - setInterval:sender { int i, max; i = [sender intValue]; max = (int) [slider maxValue]; if( i < 0 ){ i = 0; } else if( i > max ){ i = max; } [slider setIntValue:i]; [intervalField setIntValue:i]; interval = i; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.