it's kind of depressing to realize that I am like 95% of the developers out there, in that:What Tyler is forgetting is why most developers suck at threads. (And it's not just another example of Sturgeon's Law either, though that has something to do with it.)
i suck at threads.
sleep or usleep in threaded code to ensure that a dependent operation completes, instead of using a monitor. For example, by declaring a variable and checking its value in a loop rather than using a platform-provided lock (whether a blocking or spinning variant). Well, in Cincom Smalltalk, this model gives you predictability - you know exactly what a thread is going to do. The issue with runaway threads rarely comes up for a simple reason - most processes end up pausing for I/O (user input, db access, file access, sockets - what have you). That wait for I/O state is what prevents a problem from arising.This is a classic problem and I'm honestly surprised to find out that Cincom Smalltalk implements cooperative user-level threads rather than supporting preemptive kernel threads.
One issue with cooperative threads relative to preemptive OS-supplied threads is that you get far less opportunity for true concurrency within an application. In an era when multi-core processors are becoming significantly more common, this is becoming exceptionally important to application developers. It's not just about doing I/O concurrently with other operations or allowing an application to perform multiple tasks at once; it's about allowing a task to be completed faster because more efficient use is being made of machine resources. This is why I take an extremely skeptical view of user-level threading packages, especially in software built on platforms that have reasonable kernel-level threading.You'll note that the various threading APIs in Mac OS X are all built on kernel threads.
I just figured I would take some time out for a public-service announcement.
If you're developing Mac OS X software, you should really be on the appropriate developer mailing lists. Apple hosts a number of mailing lists at lists.apple.com and hosts archives there too. The lists are managed with GNU Mailman and have its convenient subscription and administration interface.
In my opinion, the principal lists for application developers are:
| carbon-dev | Developing software with the Carbon framework. |
| cocoa-dev | Developing software with the Cocoa framework. |
| java-dev | Developing software for Mac OS X in Java. |
| webobjects-dev | Developing web applications with WebObjects and EOF. |
| xcode-users | Using the Xcode Tools suite for Mac OS X development. |
There are also a whole lot of task- and technology-specific lists, including lists for developers implementing AppleScript support in applications, developers working with networking, developers creating device drivers, developers writing multithreaded applications, developers working with Xgrid...
Be sure to look through the list of lists to see what else you can take part in.
The MTA [Multiple-Threaded Apartment] is effectively a free-threaded model. (It’s not quite a free-threaded model, because STA [Single-Threaded Apartment] threads aren’t strictly allowed to call on MTA objects directly). From an efficiency point of view, it is the best threading model. Also, it imposes the least semantics on the application, which is also desirable. The main drawback with the MTA is that humans can’t reliably write free-threaded code.Uh, what?
Well, a few developers can write this kind of code if you pay them lots of money and you don’t ask them to write very much. And if you code review it very carefully. And you test it with thousands of machine hours, under very stressful conditions, on high-end MP machines like 8-ways and up. And you’re still prepared to chase down a few embarrassing race conditions once you’ve shipped your product.
setjmp and longjmp for exception handling, and neither the language nor the framework had built-in thread synchronization primitives. (Cocoa did have several classes providing synchronization functionality though.) NS_DURING
{
...
[NSException raise:NSInvalidArgumentException
format:@"Invalid argument '%@' to method 'blah'", argument];
...
}
NS_HANDLER
{
if ([[localException name] isEqualToString:NSInvalidArgumentException]) {
// handle the exception
} else {
[localException raise]; // re-raise the exception
}
}
NS_ENDHANDLER @try {
...
@throw [[[MyInvalidArgumentException alloc] init] autorelease];
...
}
@catch (MyInvalidArgumentException *invalidArgumentException) {
// handle the exception
@throw; // re-throw the exception if it wasn't handled
}
@catch (id allOtherExceptions) {
// all other exceptions will be caught by this general construct,
// or if it isn't used, they'll be caught higher up the call chain
// just like in Java or C++
}
@finally {
// do any cleanup that needs to be done regardless of whether
// an exception was thrown
}synchronized keyword; the only thing supported are blocks synchronized on a single object. But that's plenty because it means you no longer have to maintain your own NSLock for simple synchronization: NSMutableArray *sharedQueue = [[NSMutableArray alloc] initWithCapacity:5];
...
@synchronized (sharedQueue) {
// add an element to the shared queue
[sharedQueue addObject:object];
}
...
@synchronized (sharedQueue) {
// remove an element from the shared queue
if ([sharedQueue count] > 0) {
element = [sharedQueue removeObjectAtIndex:0];
}
}See? Much more straightforward than managing a separate NSLock. (Of course, for shared work queues you're generally better off using an NSConditionLock but this is just an illustration...)