Concepts of Programming Languages

(Sean Pound) #1
13.8 C# Threads 613

explicit locks are used when it is not convenient to have the lock-unlock pairs
block structured. Implicit locks are always unlocked at the end of the compound
statement in which they are locked. Explicit locks can be unlocked anywhere
in the code, regardless of the structure of the program.
One danger of using explicit locks (and is not the case with using implicit
locks) is that of omitting the unlock. Implicit locks are implicitly unlocked at
the end of the locked block. However, explicit locks stay locked until explicitly
unlocked, which can potentially be never.
As stated previously, each object has an intrinsic condition queue, which
stores threads waiting for a condition on the object. The wait, notify, and
notifyAll methods are the API for an intrinsic condition queue. Because
each object can have just one condition queue, a queue may have threads in it
waiting for different conditions. For example, the queue for our buffer example
Queue can have threads waiting for either of two conditions (filled ==
queSize or filled == 0). That is the reason why the buffer uses notify-
All. (If it used notify, only one thread would be awakened, and it might be
one that was waiting for a different condition than the one that actually became
true.) However, notifyAll is expensive to use, because it awakens all threads
waiting on an object and all must check their condition to determine which
runs. Furthermore, to check their condition, they must first acquire the lock
on the object.
An alternative to using the intrinsic condition queue is the Condition
interface, which uses a condition queue associated with a Lock object. It also
declares alternatives to wait, notify, and notifyAll named await, sig-
nal, and signalAll. There can be any number of Condition objects with
one Lock object. With Condition, signal, rather than signalAll, can be
used, which is both easier to understand and more efficient, in part because it
results in fewer context switches.

13.7.8 Evaluation


Java’s support for concurrency is relatively simple but effective. All Java run
methods are actor tasks and there is no mechanism for communication, except
through shared data, as there is among Ada tasks. Because they are heavyweight
threads, Ada’s tasks easily can be distributed to different processors; in particu-
lar, different processors with different memories, which could be on different
computers in different places. These kinds of systems are not possible with
Java’s threads.

13.8 C# Threads


Although C#’s threads are loosely based on those of Java, there are significant
differences. Following is a brief overview of C#’s threads.
Free download pdf