I am quite familar with the Ada approach, since I teach Ada...|
First it shouldbe noted that Ada (this Ada95, the current version) supports not just "tasks" - which are the Ada facility for concurrency, and communicate via rendezvous - but also "protected objects" which are passive data structures which are guarded from concurrent access. These support relatively cheap semaphores and semaphore-like capabilites.
I find it takes a bit of time to "get the idea," and to start using tasks correctly. The most common mistake, in my experience, is that people tend to forget that the task itself is sequential, and assume the task can execute more than one request at a time. This is the first step to making a complete mess of the control flow inside the task.
After you graps the way things are working (and it is a "small idea" that can understood in one chunk), things get much easier than using models that require the use of OS routines.
I am not too famliar with other concrrent langauges (aside from ASM/370...) to give a meaningful assessment.
You can take a look at AdaPower to find some Ada code, or I can post here some simple example code, if you wish.
Another good source is the Ada Rationales. The Ada83 Rationale has a good discussion of Ada tasking, and the Ada 95 Rationale explains the reasoning behind the addtion of protected types.