CS-332 Gerbessiotis, Alex       March 13, 2026  
------------------------------------------------

Note: If you see reference to a Readme1st.txt
      or just Readme1st it is this file
      named Readmej0.txt and the 0 is a reference
      to Subject 0.


1. Introduction

1.a In order to compile a specific thread file you have two options
    do first

  %  cp Makefile.thread Makefile

  If you forget every make command must include a -f Makefile.thread
  (Example:

   %  make clean -f Makefile.thread ; make all -f Makefile.thread

(a) read the Makefile, understand and use it, by compiling massively
    as in

      %  make clean; make all

    Note:  thread0X.c generates executable file t0X.

(b) compile an individual file by using the

  (i)  a gcc specific option directive -pthread  as follows

      %  gcc thread01.c -pthread -o t01

  (ii) a gcc pthread library invocation (-lpthread) that works
       on other platforms and this one is RECOMMENDED TO USE
       and the canonical form for gcc compilation

      %  gcc thread01.c -lpthread -o t01


  One is identical to the other; the latter however is standard form.

  In either case the executable file has alias    t01.

-----------------------------------------------------

2. Some notes about the code and suggestions

 Note 1: #include <pthread.h> 
 It must be the first line of a source file related to pthreads

 Note 2: Most of the code assumes that every thread is 
 joinable and thus uses a join at the end. 
 This default behavior might not be generically acceptable.
 Then you may need to make sure that your code includes 
 statements that change thread behavior. This involves
 statements or pthread functions  such as
 pthread_attr_t  attr;
 pthread_attr_init ( &attr );
 pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_JOINABLE);
 pthread_attr_destroy( &attr )

   An example is provided say in thread03.c and also thread08.c


--------------------------------------------------------------------

3. List of files thread01.c - thread08.c and thread11.c-thread13.c


FILES 
--------------------------------------------------------------------
thread01.c  : Simple two-thread creation ; three threads of execution
thread02.c  : Modifying thread01.c to prove that there are 3 threads
              of execution!
thread03.c  : use of pthread_attr_* function call(s); JOINABLE threads
thread04.c  : mutex example; global variable globalid  ->myid + id from msg[]
thread05.c  : mutex example; passing by reference tid[]->myid 
thread06.c  : mutex example; global variable globalid  ->myid + id from tdata[]
thread07.c  : thread06.c with mutex order rearranged!
thread08.c  : Inner-Product of two vectors 

thread11.c  : PI (serial+threaded)           using a SUM (Calculus I)
thread12.c  : PI (Monte-Carlo approximation) using rand_r() : jacketed rand()
thread13.c  : PI (Monte-Carlo approximation) using rand()   : no jacketing!

  It seems rand()  is not thread safe; rand_r might be.

thread22.c  : A replacement for thread02.c; Up to 5 threads possible!
thread23.c  : A replacement for thread03.c: a thread retrieves its
              attributes
thread24.c  : A replacement for thread04.c; Up to 5 threads possible!
              (A lock=0 indicates a lock has been acquired, a lock!=0
               indicates an error).

thread29.c  : New setup that can be used by thread1[123].c
              It computes in parallel (multi threading) the sum
              sum_{i=1}^{n} i = n*(n+1)/2
              Command line control of t (number of threads to be
              created) and n (must be multiple of t, but easy to
              change the code to deal with an n NOT a multiple of t)
--------------------------------------------------------------------

4.  SCALABILITY STUDY for thread11.c - thread13.c

Compile multithreaded versions of thread11.c  - thread13.c 
using individually

  % make clean; make all11
  % make clean; make all12
  % make clean; make all13

or  massively

  % make clean; make all1

but the following also works!
  % make clean; make all

It will create for example for thread11.c  4 executable files:
a single-threaded, two-threaded, 4-threaded, and 8-threaded file
named t111 , t112, t114, t118 respectively.

Run using as second argument a number equal to the number of
points in the approximation of pi or the number of terms in it.
Make the number smaller if execution time is longer.
Make sure number is a multiple of the number of thread (code
might work also for the case that it is not).

 % ./t111 1000000000

To time the execution

 % time ./t111 1000000000

The real time is of interest.

For an 8-threaded execution the second arguments indicates the
total number of points; every thread will work on 1/8 of those
points.
 % ./t118 1000000000

Food for thought. Compare the execution
 % ./t122 10000000
vs
 % ./t132 10000000
to realize the effects and improvements of jacketing.



--------------------------------------------------------------------
5.  THREADS and PROCESSES in UNIX and LINUX : tasks



 5.1 Unix Processes and Linux Processes

  Process                            Thread
  -----------------------------------------------------------------
                               |
  ProcessorState               |     ProcessorState of its own
                               |
                               |
  User   Stack                 |     User Stack     of its own
  Kernel Stack                 |     Kernel Stack   of its own
                               |
                               |
  text                         |      of the process
  init (init   global vars)    |      of the process
  bss  (uninit global vars)    |      of the process
  heap                         |      of the process
  sharedmem                    |      of the process
                               |
  Files, Lock,Sockets          |      of the process
  ------------------------------------------------------------------

  ProcessorState : includes register file, interrupts, signals.

  .  a thread shares (text, init,bss,heap,sharedmem) with the
     process that created the thread

  .  If a process dies, threads associated with it die.

  .  If a thread of a process forks, thread specific info is
     inherited by the child process but everything else from the 
     'parent process' that created the forking thread. 
     The child process is one thread of execution. 
     DO NOT EXPLORE this FURTHER!

 A process that creates two threads has three threads of execution 
 i.e. three processor_states and example thread02.c highlights this:
  - the original thread of execution of the process
  - the additional two threads of execution, one per created thread.

 Performance wise a  pthread_create() is 10-20x faster than a fork().

5.2  LINUX TASKS
--------------------------------------------------------------------

 ....  THE DISCUSSION BELOW IS DISORIENTING ....
 ....  THE DISCUSSION BELOW IS DISORIENTING ....
 ....  THE DISCUSSION BELOW IS DISORIENTING ....
 ....  THE DISCUSSION BELOW IS DISORIENTING ....
 ....  THE DISCUSSION BELOW IS DISORIENTING ....
 ....  THE DISCUSSION BELOW IS DISORIENTING ....



The linux kernel deals with tasks. 
Every task is a linux process (lp).
A task is 
     a traditional process (tp) or 
     a traditional thread (tt).

A traditional process is per definition of Subject 1,2,3.
A traditional thread  is per definition of Subject 1,2,3,4.


A tp is a linux task. 

A tt is a linux task. 

What makes a linux task distinct and unique is the Linux-PID since 
every task in linux is a linux process (lp).  
Every tp and tt in linux is assigned a unique Linux-PID.


[TRADITIONAL PROCESS]

When a tp is created in LINUX it is assigned a unique
      LINUX-PID (linux-process ID) and a 
      TGID      (thread group ID). 
They are identical. Thus a tp can be recognized 
      from having TGID == LINUX-PID.

Example. 
      A tp is created. Its LINUX-PID=10  and  TGID=10.

[TRADITIONAL THREAD] 

When a tt is created in LINUX it is assigned a unique 
      LINUX-PID (linux-process ID) and a
      TGID      (thread group ID). 
The TGID is the one identifying the tp to which the tt belongs.

Example.  
      The tp (LINUX-PID=10,TGID=10) creates a thread (tt). 
      The thread is assigned LINUX-PID=11 but TGID=10. 
      Since TGID != LINUX-PID it is not a tp but it is a tt.

Example. 
      The two tasks created are treated by LINUX as processes 
      and are scheduled as processes. 
      They have two distinct LINUX-PID  10 and 11 respectively.


[ LINUX  getpid() and gettid()  return TGID's not LINUX-PIDs]

[LINUX getpid() returns TGID  i.e. the PID         of Subject 3,4]
[LINUX gettid() returns LINUX-PID i.e. the task ID of Subject 3,4 ]

 In linux getpid() returns ... the TGID of the task. 

Example
  Thus in the task with TGID=10  getpid() returns a 10. 
  In      process  with TGID=10  getpid() returns a 10.
  Thus getpid() returns TGID which is the PID of Subject 1,2,3,
  both in the process and in all of its tasks.

  In linux gettid() returns ... the LINUX-PID of the task.
  Thus in the task with LINUX-PID=10  gettid() returns a  10.
  In          task with LINUX-PID=11  gettid() returns an 11.

  The PID of Subjects 3,4 is returned by getpid() 
  but in linux it is maintained in TGID. 
  The LINUX-PID contains a unique-ID that is 
  available to the caller through gettid().
