Thread of
execution in a
program
- A running program
is commonly known as:
- Each process has
at least
one (1)
thread of execution:
- Executing a
C/Java program:
- Initially, there is
one
thread of execution
- The
thread of execution
starts with the
main( )
function
- The
thread of execution
follows the
program flow in the
C/Java program
|
|
Single-threaded execution
- A
process that
has
one
thread of execution has a:
- Single-threaded
execution
|
- A
Shared Memory MIMD computer can
execute
multiple
single-threaded
processes:
- As we have
discussed before:
- This is
not
parallel programming
|
|
Multi-threaded execution and
parallel programming
- A
process that
has
more than one
thread of execution has a:
- In
parallel programming
the
different
threads
cooperate in
the computation:
- In order to
cooperate:
- Threads
must
share information
with each other
|
|
Intro to
multi-threaded programming using
Posix Threads
Your first
multi-threaded
C program
- Let's write a
multi-threaded
C program:
#include <stdio.h>
#include <pthread.h>
void *worker(void *arg)
{
for (int i = 0; i < 10000000; i++)
{
for (int j = 0; j < 10000000; j++); // Slow thread down...
printf("*");
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
pthread_t tid;
// This program just prints a lot of dots....
for (int i = 0; i < 10000000; i++)
{
for (int j = 0; j < 20000000; j++); // Slow main down...
printf(".");
fflush(stdout);
}
}
|
|
Your first
multi-threaded
C program
- A pthread
C program must
include the
pthread.h
header file
#include <stdio.h>
#include <pthread.h>
void *worker(void *arg)
{
for (int i = 0; i < 10000000; i++)
{
for (int j = 0; j < 10000000; j++); // Slow thread down...
printf("*");
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
pthread_t tid;
pthread_create(&tid, NULL, worker, NULL); // Create thread
for (int i = 0; i < 10000000; i++)
{
for (int j = 0; j < 20000000; j++); // Slow main down...
printf(".");
fflush(stdout);
}
}
|
|
Your first
multi-threaded
C program
Your first
multi-threaded
C program
Compiling
a multi-threaded C program
DEMO:
demo/pthread/intro.c
Visualizing the
multi-threaded program
Visualizing the
multi-threaded program
Visualizing the
multi-threaded program
Difference between
PThreads and
CUDA threads
- PThreads:
- A PThread is
created to
execute
some
function
- Different
threads can
execute
different
functions....
|
- Therefore: each
thread is
independent from
each other
-
Instructions
executed by
different threads
are
"unrelated"
|
|
- CUDA threads:
- A
grid of
threads is
launched to
execute
one
kernel
function.
- Therefore: every
thread
in the grid
will:
- execute the
same
sequence
of
instructions
|
|
|
Thread ID
of a thread
- Each thread
has a unique
thread id
- The function
pthread_self( )
returns the
thread id
of a thread
|
- The
main
thread is
created when a
program
starts running
- The
main
thread is
also a
thread and
has a
thread id
|
Example:
void *worker(void *arg)
{
printf("Worker: my thread id = %ld\n", pthread_self());
}
int main(int argc, char *argv[])
{
pthread_t tid;
pthread_create(&tid, NULL, worker, NULL) != 0 ) // Create thread
printf("Main: my thread id = %ld\n", pthread_self());
}
|
|
DEMO:
demo/pthread/thread-id.c
Variable sharing
among the threads
-
Global variables
are
shared
among
all
threads
- All
threads uses
the
same copy of the
global variable
|
-
Local variables
defined in
functions
executed by
a thread
are
private:
- Each thread
has
its own copy
of
the local variable
|
Example:
int N = 4444; // Shared among all threads
void *worker(void *arg)
{
int i = 99; // Each thread has its own copy
printf("Worker: N = %d, i = %d\n", N, i);
}
int main(int argc, char *argv[])
{
pthread_t tid;
int i = 86; // Each thread has its own copy
pthread_create(&tid, NULL, worker, NULL);
printf("Worker: N = %d, i = %d\n", N, i);
}
|
|
DEMO:
demo/pthread/sharing-vars.c
Background info:
concurrent updates to
shared variables
The
concurrent updates to
shared variables
- Consider the
concurrent updates to
a
shared variable N
by 2 threads where
each thread
increments N
100,000 times:
int N = 0;
void *worker(void *arg)
{
for ( int i = 0; i < 100000; i++)
N++;
}
int main(int argc, char *argv[])
{
pthread_t tid;
pthread_create(&tid, NULL, worker, NULL);
for ( int i = 0; i < 100000; i++)
N++;
sleep(1);
printf("Final value: N = %d\n", N);
}
|
- Result:
you can get
different
final value
for N with
different runs...
|
DEMO:
demo/pthread/sharing-vars2.c
Explaining the results of the
concurrent updates to
shared variables
Explaining the results of the
concurrent updates to
shared variables
- Example
of the effect of
a unsynchronized execution
of parallel threads:
Time Memory Thread 1 Thread 2
---- --------- -------------- --------------
| N = 12 ldr N --> 12
| add 1 --> 13 ldr N --> 12
| N = 13 str N add 1 --> 13
| N = 13 str N
V Missing increment N (because Thread 2 used an "old" value)
|
- Explaination:
- Initially, the
variable N contains
the value 12
(for example)
- Thread 1
obtained the
value 12 when the
ldr instruction
was executed
because the variable N
has the value 12
- Thread 1
add 1 to
it's copy
(in it's register r1)
while....
Thread 2
obtained the
value 12 when the
ldr instruction
was executed
because the variable N
still
has the value 12
- Thread 1
updates the
variable N
to 13
while....
Thread 2
add 1 to
it's copy
(in it's register r1)
- Thread 2
updates the
variable N
to 13
|
|
❮
❯