  Threading and Kernel threads questions? 
 The Question is:
 
Dear Wizard,
 
I am having difficulty grasping the the "kernal"
thread concept.  I have written serveral
programs taking advantage of the
PTHREADS interface.  I understand the two-
level schedualing and virtual processors.
Even "UPCALLS" make sense to me. No problem!  What makes a thread a "KERNAL"
thread?
When should I use the thread linker
options: THREADS_ENABLE.,
/THREADS_ENABLE=MULTIPLE_KERNAL_THREADS
/THREADS_ENABLE=UPCALLS
 
I have written a print server (sort of; there's
actually a little more than printing involved), which creates a thread for
each client (TCP).  When a "print" request is received, the client thread
scans a list of worker threads for an available worker.  When a worker
thread is found the client thread a
ssigns it the job to the
worker.  If no workers are available, a new
worker thread may be created if the
"configured maximum" has not been reached.
 
1) How do I determine how many worker threads should be allowed?  At some
point
they must to cost more than they're worth.
    Are there any formulas based on # of clents and processors etc....?  How
might I measure
the effectivness of this model?
2) Which linker options should I be using?
3) What about "multiple kernal threads"?  What is the difference between a
"thread" and a kernal thread?
 
Please provide any insight that you possess on this subject.
 
Thank,
 
John
 
 
 The Answer is:
Given that you understand two-level scheduling and virtual processors, then
answering your first question is easy:  from your perspective, a "kernel thread"
is a virtual processor.  On the other hand, from the operating system
perspective, a "kernel thread" is the context required by the operating system
kernel to schedule execution on a processor.  So, in concrete terms, if you link
your program without enabling multiple kernel threads, then DECthreads will
create only one virtual processor; however, if you enable multiple kernel
threads, then DECthreads will create as many virtual processors has there are
CPUs on the machine.  Thus, in order to achieve true parallel execution, your
application must be linked /THREADS and run on an SMP Alpha machine.
 
With respect to commenting on your printserver model, the answers are,
unfortunately, more fuzzy.  Your general approach seems pretty reasonable,
although this Wizard prefers a self-scheduling model (i.e., put the new work
item in a queue and signal a condition variable; have workers wait on the
condition variable for work; create extra workers if all are busy and the count
is less than the "configured maximum"), because it's simpler than scanning the
list of threads and having to synchronize with the one which is to receive the
item.
 
Regarding determining the maximum number of worker threads, there is no hard and
fast formula which will yield the answer.  The right number depends on the
behavior of the threads while they are actively processing a task.  If they are
completely compute-bound, then there is probably no point in having more worker
threads than there are available CPUs.  However, if they perform a mixture of
compute activity and blocking activity (i.e., blocking for I/O or on condition
variables -- don't count mutex waits, which should be short), then there is an
opportunity to support more workers.  This Wizard would recommend tuning based
on testing.
 
Regarding the choice of linker options, the answer depends on the requirements
of the application and the components which it uses.  Linking /NOTHREADS (which
is the default), is least likely to trigger problems due to lack of thread-safe
code; on the other hand, it also results in the application using only one CPU
and in unpleasant latencies in blocking system service calls, such as for I/O.
The latencies can be addressed by linking /THREADS=UPCALLS, and this will
generally not disturb other parts of the code (although it typcially does
substantially change execution timing relative to /NOTHREADS, and this might
expose latent bugs).  Nevertheless, if your code will tollerate it, this Wizard
heartily recommends linking /THREADS (which implies both UPCALLS and
MULTIPLE_KERNEL_THREADS), as this gives your program best access to the full
capabilities of the machine.
 
Please, note that turning on upcalls does make certain operations (e.g., AST
delivery) more expensive.  The expectation is that the performance loss due to
the additional overhead will be more than made up for by removing the blocking
latencies and improving the parallelism of the application execution.  However,
some performance testing might be in order before deciding whether to enable
upcalls or not.  (Note that DECthreads will not create multiple virtual
processors if upcalls are disabled, because DECthreads cannot provide an
environment for the application which is "culturally consistent" if there are
multiple kernel threads without upcalls.)
 
 
