+ All Categories
Home > Documents > Shared-Memory Programming with Threads

Shared-Memory Programming with Threads

Date post: 30-Dec-2015
Category:
Upload: burke-ashley
View: 49 times
Download: 0 times
Share this document with a friend
Description:
Shared-Memory Programming with Threads. Adapted and edited by Aleksey Zimin from http://navet.ics.hawaii.edu/~casanova/courses/ics632_fall07/slides/ics632_threads.ppt http://users.actcom.co.il/~choo/lupg/tutorials/multi-process/multi-process.html#process_creation_fork_syscall. - PowerPoint PPT Presentation
59
Shared-Memory Shared-Memory Programming Programming with Threads with Threads Adapted and edited by Aleksey Adapted and edited by Aleksey Zimin from Zimin from http://navet.ics.hawaii.edu/ http://navet.ics.hawaii.edu/ ~casanova/courses/ics632_fall07/ ~casanova/courses/ics632_fall07/ slides/ics632_threads.ppt slides/ics632_threads.ppt http://users.actcom.co.il/~choo/ http://users.actcom.co.il/~choo/ lupg/tutorials/multi-process/multi- lupg/tutorials/multi-process/multi- process.html#process_creation_fork_sy process.html#process_creation_fork_sy scall scall
Transcript
Page 1: Shared-Memory Programming with Threads

Shared-Memory Shared-Memory ProgrammingProgrammingwith Threadswith Threads

Adapted and edited by Aleksey Adapted and edited by Aleksey Zimin from Zimin from

http://navet.ics.hawaii.edu/~casanova/http://navet.ics.hawaii.edu/~casanova/courses/ics632_fall07/slides/courses/ics632_fall07/slides/

ics632_threads.ppt ics632_threads.ppt http://users.actcom.co.il/~choo/lupg/http://users.actcom.co.il/~choo/lupg/

tutorials/multi-process/multi-tutorials/multi-process/multi-process.html#process_creation_fork_syscalprocess.html#process_creation_fork_syscal

ll

Page 2: Shared-Memory Programming with Threads

Parallel ApplicationsParallel Applications

Modern computers have multiple Modern computers have multiple CPU cores (and/or multiple CPUs) on CPU cores (and/or multiple CPUs) on boardboard

We have to be able to utilize the We have to be able to utilize the computing power by parallelizing computing power by parallelizing our tasks our tasks

Page 3: Shared-Memory Programming with Threads

CPU InformationCPU Information Linux computer: /proc/cpuinfoLinux computer: /proc/cpuinfo Cat /proc/cpuinfo example:Cat /proc/cpuinfo example:

processor : 0processor : 0vendor_id : AuthenticAMDvendor_id : AuthenticAMDcpu family : 15cpu family : 15model : 65model : 65model name : Dual-Core AMD Opteron(tm) Processor 8220model name : Dual-Core AMD Opteron(tm) Processor 8220stepping : 3stepping : 3cpu MHz : 2800.000cpu MHz : 2800.000cache size : 1024 KBcache size : 1024 KBphysical id : 0physical id : 0siblings : 2siblings : 2core id : 0core id : 0

cpu cores : 2cpu cores : 2fpu : yesfpu : yesfpu_exception : yesfpu_exception : yescpuid level : 1cpuid level : 1wp : yeswp : yesflags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht

syscall nx mmxext fxsr_opt rdtscp lm 3dnowext 3dnow pni cx16 lahfsyscall nx mmxext fxsr_opt rdtscp lm 3dnowext 3dnow pni cx16 lahf_lm cmp_legacy svm extapic cr8_legacy_lm cmp_legacy svm extapic cr8_legacybogomips : 5625.16bogomips : 5625.16TLB size : 1024 4K pagesTLB size : 1024 4K pagesclflush size : 64clflush size : 64cache_alignment : 64cache_alignment : 64address sizes : 40 bits physical, 48 bits virtualaddress sizes : 40 bits physical, 48 bits virtualpower management: ts fid vid ttp tm stcpower management: ts fid vid ttp tm stc

Page 4: Shared-Memory Programming with Threads

Processes in UNIXProcesses in UNIX UNIX is natively parallel operating UNIX is natively parallel operating

systemsystem

A A processprocess is an instance of running a is an instance of running a program program

Each process has a unique Each process has a unique process idprocess id

Shell command “ps” gives the list of all Shell command “ps” gives the list of all running processesrunning processes

Page 5: Shared-Memory Programming with Threads

Using the shell Using the shell commandscommands

In any UNIX shell, “&” will run the In any UNIX shell, “&” will run the command in background. command in background.

The command will run in its own shell, The command will run in its own shell, which is a child of the current shellwhich is a child of the current shell

[alekseyz@genome10]$ run_command.sh &[alekseyz@genome10]$ run_command.sh &

““wait” command will wait for all child wait” command will wait for all child processes in the current shell to finishprocesses in the current shell to finish

Page 6: Shared-Memory Programming with Threads

Example of & and waitExample of & and wait In bash:In bash:#!/bin/bash#!/bin/bashlet NUM_CPUS=`cat /proc/cpuinfo |grep processor|tail -1|awk '{print $NF+1}'`let NUM_CPUS=`cat /proc/cpuinfo |grep processor|tail -1|awk '{print $NF+1}'`let counter=1;let counter=1;let cpu_counter=1;let cpu_counter=1;echo "Total processes to run:"$1echo "Total processes to run:"$1echo "Simultaneously running:"$NUM_CPUSecho "Simultaneously running:"$NUM_CPUS

while [[ $counter -le $1 ]];dowhile [[ $counter -le $1 ]];dowhile [[ $cpu_counter -le $NUM_CPUS && $counter -le $1 ]];dowhile [[ $cpu_counter -le $NUM_CPUS && $counter -le $1 ]];do

./echo_sleep_echo.sh &./echo_sleep_echo.sh & let counter=$counter+1let counter=$counter+1 let cpu_counter=$cpu_counter+1;let cpu_counter=$cpu_counter+1; donedone let cpu_counter=1;let cpu_counter=1; waitwaitdonedone------------------------------------------------------------------------------------------------------------------------------------------------------#!/bin/bash#!/bin/bashecho "Sleeping 10 seconds in shell "$$echo "Sleeping 10 seconds in shell "$$sleep 10sleep 10echo "Done"echo "Done"

Page 7: Shared-Memory Programming with Threads

Using fork() and wait() in Using fork() and wait() in CC

The fork() system call is the basic way to The fork() system call is the basic way to create a new process. fork() is used to produce create a new process. fork() is used to produce child shell.child shell.

Returns twice(!!!!)Returns twice(!!!!) fork() causes the current process to be split fork() causes the current process to be split

into two processes - a parent process, and a into two processes - a parent process, and a child process. child process.

All of the memory pages used by the original All of the memory pages used by the original process get duplicated during the fork() call, process get duplicated during the fork() call, so both parent and child process see the so both parent and child process see the exact exact same memory imagesame memory image. .

Page 8: Shared-Memory Programming with Threads

fork() continuedfork() continued When fork() returns in the parent process, its When fork() returns in the parent process, its

return value is the process ID (PID) of the return value is the process ID (PID) of the child process. child process.

When it returns inside the child process, its When it returns inside the child process, its return value is '0'. return value is '0'.

If for some reason fork() failed (not enough If for some reason fork() failed (not enough memory, too many processes, etc.), no new memory, too many processes, etc.), no new process is created, and the return value of process is created, and the return value of the call is '-1'. the call is '-1'.

Both child process and parent process Both child process and parent process continue from the same place in the code continue from the same place in the code where the fork() call was used. where the fork() call was used.

Page 9: Shared-Memory Programming with Threads

Child processesChild processes When a child process exits, it sends a signal to its When a child process exits, it sends a signal to its

parent process, which needs to acknowledge it's parent process, which needs to acknowledge it's child's death. During this time the child process is child's death. During this time the child process is in a state called in a state called zombiezombie. .

When a process exits, if it had any children, they When a process exits, if it had any children, they become become orphansorphans. An orphan process is . An orphan process is automatically inherited by the automatically inherited by the initinit process, and process, and becomes a child of this becomes a child of this initinit process. process.

When the parent process is not properly coded, When the parent process is not properly coded, the child remains in the zombie state forever. Such the child remains in the zombie state forever. Such processes can be noticed by running the “ps” processes can be noticed by running the “ps” command, and seeing processes having the string command, and seeing processes having the string "<defunct>" as their command name. "<defunct>" as their command name.

Page 10: Shared-Memory Programming with Threads

Simple fork() and wait() Simple fork() and wait() exampleexample#include <stdio.h>#include <stdio.h>

#include <unistd.h> /* defines fork(), and pid_t. */#include <unistd.h> /* defines fork(), and pid_t. */#include <sys/wait.h> /* defines the wait() system call. */#include <sys/wait.h> /* defines the wait() system call. */int main(){int main(){pid_t child_pid; pid_t child_pid; int child_status;int child_status;

child_pid = fork(); child_pid = fork(); switch (child_pid) {switch (child_pid) { case -1:case -1: perror("fork"); perror("fork"); exit(1);exit(1); case 0:case 0: printf("I am the child, Hello world\n");printf("I am the child, Hello world\n"); sleep(10);sleep(10); exit(0); exit(0); default:default: printf("I am the parent, waiting for the child process %d to exit... printf("I am the parent, waiting for the child process %d to exit...

\n",child_pid);\n",child_pid); wait(&child_status); wait(&child_status); printf("I am the parent, child process %d exited with status %d\printf("I am the parent, child process %d exited with status %d\

n",child_pid,child_status);n",child_pid,child_status); }}}}

Page 11: Shared-Memory Programming with Threads

InterProcess InterProcess communicationcommunication

One can prescribe what each child One can prescribe what each child does in the fork() calldoes in the fork() call

It is helpful if parent could It is helpful if parent could communicate with child (e.g. report communicate with child (e.g. report progress, get data)progress, get data)

Easiest way for parent and child to Easiest way for parent and child to communicate is through communicate is through pipepipe

Page 12: Shared-Memory Programming with Threads

Using pipesUsing pipes Anonymous pipe:Anonymous pipe: A pipe is a one-way A pipe is a one-way

mechanism that allows two related processes mechanism that allows two related processes (i.e. one is an ancestor of the other) to send a (i.e. one is an ancestor of the other) to send a byte stream from one of them to the other byte stream from one of them to the other one. one.

The order in which data is written to the The order in which data is written to the pipe, is the same order as that in which data pipe, is the same order as that in which data is read from the pipe. is read from the pipe.

The system assures that data won't get lost in The system assures that data won't get lost in the middle, unless one of the processes (the the middle, unless one of the processes (the sender or the receiver) exits prematurely. sender or the receiver) exits prematurely.

Page 13: Shared-Memory Programming with Threads

pipe()pipe()

The pipe() system call is used to The pipe() system call is used to create a read-write pipe. create a read-write pipe.

pipe() takes as an argument an array pipe() takes as an argument an array of 2 integers that will be used to of 2 integers that will be used to save the two file descriptors used to save the two file descriptors used to access the pipe. The first to read access the pipe. The first to read from the pipe, and the second to from the pipe, and the second to write to the pipe. write to the pipe.

Page 14: Shared-Memory Programming with Threads

Using pipe()Using pipe()/* first, define an array to store the two file /* first, define an array to store the two file

descriptors */ descriptors */ int pipes[2]; int pipes[2];

/* now, create the pipe */ /* now, create the pipe */ int rc = pipe(pipes); int rc = pipe(pipes);

if (rc == -1) if (rc == -1) { { /* pipe() failed */ /* pipe() failed */ perror("pipe"); perror("pipe"); exit(1); exit(1); }}

Page 15: Shared-Memory Programming with Threads

pipe() example -- mainpipe() example -- mainint main() int main() { { int data_pipe[2]; /* an array to store the file descriptors of the int data_pipe[2]; /* an array to store the file descriptors of the

pipe. */ pipe. */ int pid; int pid; int rc; int rc;

rc = pipe(data_pipe); rc = pipe(data_pipe); if (rc == -1) { perror("pipe"); exit(1); }if (rc == -1) { perror("pipe"); exit(1); }

pid = fork(); pid = fork(); switch (pid) switch (pid)

{ { case -1: case -1:

perror("fork"); exit(1); perror("fork"); exit(1); case 0: case 0:

do_child(data_pipe); do_child(data_pipe); default: default:

do_parent(data_pipe); do_parent(data_pipe); }}

}}

Page 16: Shared-Memory Programming with Threads

pipe() example -- parentpipe() example -- parentvoid do_parent(int data_pipe[]) {void do_parent(int data_pipe[]) { int c; /* data received from the user. */ int c; /* data received from the user. */ int rc; int rc;

/* first, close the un-needed read-part of the pipe. */ /* first, close the un-needed read-part of the pipe. */ close(data_pipe[0]); close(data_pipe[0]);

while ((c = getchar()) > 0) while ((c = getchar()) > 0) { {

rc = write(data_pipe[1], &c, 1); rc = write(data_pipe[1], &c, 1); if (rc == -1) if (rc == -1) {{perror("Parent:write");close(data_pipe[1]);exit(1);perror("Parent:write");close(data_pipe[1]);exit(1);} }

} } close(data_pipe[1]); close(data_pipe[1]); exit(0); exit(0); } }

Page 17: Shared-Memory Programming with Threads

pipe() example -- childpipe() example -- childvoid do_child(int data_pipe[]) { void do_child(int data_pipe[]) { int c; /* data received from the parent. */ int c; /* data received from the parent. */ int rc; int rc;

/* first, close the un-needed write-part of the pipe. */ /* first, close the un-needed write-part of the pipe. */ close(data_pipe[1]); close(data_pipe[1]);

while ((rc = read(data_pipe[0], &c, 1)) > 0) while ((rc = read(data_pipe[0], &c, 1)) > 0) { {

putchar(c); putchar(c); } }

exit(0); exit(0); } }

Page 18: Shared-Memory Programming with Threads

Processes vs. threadsProcesses vs. threads Each process owns:Each process owns:

Unit of resources ownershipUnit of resources ownership Allocated with virtual address space + control of Allocated with virtual address space + control of

other resources such as I/O, files….other resources such as I/O, files…. Unit of dispatching Unit of dispatching

Execution path and state, dispatching priority.Execution path and state, dispatching priority. Controlled by OSControlled by OS

Each thread owns:Each thread owns: Unit of dispatchingUnit of dispatching

Threads share resourcesThreads share resources

Page 19: Shared-Memory Programming with Threads

CommentsComments

Traditional program is one thread per Traditional program is one thread per process. process.

The main thread starts with The main thread starts with main()main() Only one thread or program counter Only one thread or program counter

(PC) is allowed to execute the code (PC) is allowed to execute the code segmentsegment

To add a new PC, you need to To add a new PC, you need to fork() fork() to have another PC to execute to have another PC to execute in in another process address space.another process address space.

Page 20: Shared-Memory Programming with Threads

Key benefits of Key benefits of multithreadingmultithreading

Less time to create a thread than a processLess time to create a thread than a process

Less time to terminate a thread than a processLess time to terminate a thread than a process

Less time to switch a threadLess time to switch a thread

Enhance efficiency in communication: no need Enhance efficiency in communication: no need for kernel to intervenefor kernel to intervene

Smaller chance of driving you crazy while Smaller chance of driving you crazy while writing code / debuggingwriting code / debugging

Page 21: Shared-Memory Programming with Threads

Shared memory Shared memory programmingprogramming

The “easiest” form of parallel The “easiest” form of parallel programmingprogramming

Can be used to parallelize a sequential Can be used to parallelize a sequential code in an incremental way:code in an incremental way: take a sequential codetake a sequential code parallelize a small sectionparallelize a small section check that it workscheck that it works check that it speeds things up a bitcheck that it speeds things up a bit move on to another sectionmove on to another section

Page 22: Shared-Memory Programming with Threads

ThreadThread A A threadthread is a stream of instructions that is a stream of instructions that

can be scheduled as an independent unit. can be scheduled as an independent unit.

A process is created by an operating A process is created by an operating systemsystem contains information about resourcescontains information about resources

process id, file descriptors, ...process id, file descriptors, ... contains information on the execution contains information on the execution

statestate program counter, stack, ...program counter, stack, ...

Page 23: Shared-Memory Programming with Threads

Schedulable Part of a Schedulable Part of a ProcessProcess

The concept of a thread requires that we The concept of a thread requires that we make a separation between these two kinds make a separation between these two kinds of information in a processof information in a process resources available to the entire processresources available to the entire process

program instructions, global data, program instructions, global data, working directoryworking directory

schedulable entitiesschedulable entities program counters and stacks.program counters and stacks.

A thread is an entity within a processA thread is an entity within a process which which consists of the schedulable part of the consists of the schedulable part of the process.process.

Page 24: Shared-Memory Programming with Threads

Process is still there,Process is still there,what’s new for thread?what’s new for thread?

Thread shares with processThread shares with process Virtual address space (holding process image), Virtual address space (holding process image),

access to memory and resources of its process, access to memory and resources of its process, shared with all other threads in that processshared with all other threads in that process

Protected access to CPU, files, and I/O Protected access to CPU, files, and I/O resourcesresources

Thread has its ownThread has its own Thread execution stateThread execution state Saved thread context (an independent PC Saved thread context (an independent PC

within a process)within a process) Execution stackExecution stack Per-thread static storage for local variablesPer-thread static storage for local variables

Page 25: Shared-Memory Programming with Threads

Possible combination of thread and Possible combination of thread and processesprocesses

One process one threadOne process multiple thread

Multiple processes multipleThreads per process

Multiple processesOne thread per process

Page 26: Shared-Memory Programming with Threads

Parallelism with ThreadsParallelism with Threads

Create threads within a processCreate threads within a process Each thread does something Each thread does something

(hopefully) useful(hopefully) useful Threads may be working truly Threads may be working truly

concurrentlyconcurrently Multi-processorMulti-processor Multi-coreMulti-core

Or just pseudo-concurrentlyOr just pseudo-concurrently Single-proc, single-coreSingle-proc, single-core

Page 27: Shared-Memory Programming with Threads

ExampleExample

Say I want to compute the sum of two arraysSay I want to compute the sum of two arrays I can just create N threads, each of which I can just create N threads, each of which

sums 1/Nth of both arrays and then combine sums 1/Nth of both arrays and then combine their resultstheir results

I can also create N threads that each I can also create N threads that each increment some sum variable element-by-increment some sum variable element-by-element, but then I’ve got to make sure they element, but then I’ve got to make sure they don’t step on each other’s toesdon’t step on each other’s toes

The first version is a bit less “shared-The first version is a bit less “shared-memory”, but is probably more efficientmemory”, but is probably more efficient

Page 28: Shared-Memory Programming with Threads

Multi-threading issuesMulti-threading issues There are really two main issues when writing There are really two main issues when writing

multi-threaded code:multi-threaded code: Issue #1: Load BalancingIssue #1: Load Balancing

Make sure that no processors/cores is left idle when it Make sure that no processors/cores is left idle when it could be doing useful workcould be doing useful work

Issue #2: Correct access to shared variablesIssue #2: Correct access to shared variables Implemented via mutual exclusion: create Implemented via mutual exclusion: create sections of sections of

codecode that only a single thread can be in at a time that only a single thread can be in at a time Called “critical sections”Called “critical sections” Classical variable update exampleClassical variable update example

Done via “locks” and “unlocks”Done via “locks” and “unlocks” Warning: locks are NOT on variables, but on sections of Warning: locks are NOT on variables, but on sections of

codecode

Page 29: Shared-Memory Programming with Threads

User-level threads User-level threads (DOS, Windows 95)(DOS, Windows 95)

User-level threads: Many-to-one thread User-level threads: Many-to-one thread mappingmapping

Implemented by user-level runtime librariesImplemented by user-level runtime libraries Create, schedule, synchronize threads at Create, schedule, synchronize threads at

user-leveluser-level

OS is not aware of user-level threadsOS is not aware of user-level threads OS thinks each process contains only a OS thinks each process contains only a

single thread of controlsingle thread of control

Page 30: Shared-Memory Programming with Threads

User-level threadsUser-level threads

AdvantagesAdvantages Does not require OS support; PortableDoes not require OS support; Portable Can tune scheduling policy to meet Can tune scheduling policy to meet

application demandsapplication demands Lower overhead thread operations since Lower overhead thread operations since

no system callsno system calls

DisadvantagesDisadvantages Cannot leverage multiprocessorsCannot leverage multiprocessors Entire process blocks when one thread Entire process blocks when one thread

blocksblocks

Page 31: Shared-Memory Programming with Threads

Kernel-level threadsKernel-level threads

Kernel-level threads: One-to-one Kernel-level threads: One-to-one thread mappingthread mapping OS provides each user-level thread with OS provides each user-level thread with

a kernel threada kernel thread Each kernel thread scheduled Each kernel thread scheduled

independentlyindependently Thread operations (creation, Thread operations (creation,

scheduling, synchronization) performed scheduling, synchronization) performed by OSby OS

Page 32: Shared-Memory Programming with Threads

Kernel-level threadsKernel-level threads

AdvantagesAdvantages Each kernel-level thread can run in Each kernel-level thread can run in

parallel on a multiprocessorparallel on a multiprocessor When one thread blocks, other threads When one thread blocks, other threads

from process can be scheduledfrom process can be scheduled

DisadvantagesDisadvantages Higher overhead for thread operationsHigher overhead for thread operations OS must scale well with increasing OS must scale well with increasing

number of threadsnumber of threads

Page 33: Shared-Memory Programming with Threads

Threads in PracticeThreads in Practice PthreadsPthreads

Popular C libraryPopular C library FlexibleFlexible Will discuss theseWill discuss these

OpenMPOpenMP

Java ThreadsJava Threads

Page 34: Shared-Memory Programming with Threads

PthreadsPthreads

A POSIX standard (IEEE 1003.1c) API for A POSIX standard (IEEE 1003.1c) API for thread creation and synchronizationthread creation and synchronization The API specifies the standard behaviorThe API specifies the standard behavior Implementation choices are up to developersImplementation choices are up to developers Implementations vary, some better than some Implementations vary, some better than some

othersothers Common in all UNIX operating systemsCommon in all UNIX operating systems Some people have written it for Win32Some people have written it for Win32 The most portable threading library out thereThe most portable threading library out there What do threads look like in UNIX?What do threads look like in UNIX?

Page 35: Shared-Memory Programming with Threads

Using the Pthread Using the Pthread LibraryLibrary

Pthread library typically uses kernel-Pthread library typically uses kernel-threadsthreads

Programs must include the file Programs must include the file pthread.hpthread.h Programs must be linked with the pthread Programs must be linked with the pthread

library (library (-lpthread-lpthread)) The API contains functions toThe API contains functions to

create threadscreate threads control threadscontrol threads manage threadsmanage threads synchronize threadssynchronize threads

Page 36: Shared-Memory Programming with Threads

pthread_self()pthread_self() Returns the thread identifier for the Returns the thread identifier for the

calling threadcalling thread At any point in its instruction stream a At any point in its instruction stream a

thread can figure out which thread it isthread can figure out which thread it is Convenient to be able to write code that Convenient to be able to write code that

says: “If you’re thread 1 do this, otherwise says: “If you’re thread 1 do this, otherwise to that”to that”

#include <pthread.h>#include <pthread.h>

pthread_tpthread_t pthread_selfpthread_self(void);(void);

Page 37: Shared-Memory Programming with Threads

pthread_create()pthread_create() Creates a new thread of controlCreates a new thread of control

#include <pthread.h>#include <pthread.h>int int pthread_createpthread_create ( ( pthread_t *thread,pthread_t *thread,

pthread_attr_t *attr,pthread_attr_t *attr,void * (*start_routine) (void *)void * (*start_routine) (void *),,void *arg);void *arg);

Returns 0 to indicate success, otherwise returns error codeReturns 0 to indicate success, otherwise returns error code threadthread: output argument that will contain the thread id of the new : output argument that will contain the thread id of the new

threadthread attrattr: input argument that specifies the attributes of the thread to be : input argument that specifies the attributes of the thread to be

created (NULL = default attributes)created (NULL = default attributes) start_routine: start_routine: function to use as the start of the new thread must function to use as the start of the new thread must

have prototype: void * foo(void*)have prototype: void * foo(void*) arg: arg: argument to pass to the new thread routineargument to pass to the new thread routine

If the thread routine requires multiple arguments, they must be passed If the thread routine requires multiple arguments, they must be passed bundled up in an array or a structurebundled up in an array or a structure

Page 38: Shared-Memory Programming with Threads

pthread_create() examplepthread_create() example Want to create a thread to compute the sum of Want to create a thread to compute the sum of

the elements of an arraythe elements of an arrayvoid *do_work(void *arg);void *do_work(void *arg);

Needs three argumentsNeeds three arguments the array, its size, where to store the sumthe array, its size, where to store the sum we need to bundle them in a structurewe need to bundle them in a structure

struct arguments {struct arguments {long int *array;long int *array;long int size;long int size;long int *sum;long int *sum;

}}

Page 39: Shared-Memory Programming with Threads

pthread_create() examplepthread_create() exampleint main(void) {

long int array[ARRAY_SIZE], sum, i;

pthread_t worker_thread;

struct arguments *arg;

for(i=0;i<ARRAY_SIZE;i++) array[i]=1;

arg = calloc(1,sizeof(struct arguments));

arg->array = array;

arg->size=ARRAY_SIZE;

arg->sum = &sum;

if (pthread_create(&worker_thread, NULL, do_work, (void *)arg))

{

fprintf(stderr,"Error while creating thread");

exit(1);

}

...

exit(0);

}

Page 40: Shared-Memory Programming with Threads

pthread_create() examplepthread_create() examplevoid *do_work(void *arg){ long int i, size; long int *array; long int *sum;

size = ((struct arguments *)arg)->size; array = ((struct arguments *)arg)->array; sum = ((struct arguments *)arg)->sum;

*sum = 0; for (i=0;i<size;i++) *sum += array[i]; return NULL;}

Page 41: Shared-Memory Programming with Threads

Comments about the Comments about the exampleexample

The “parent thread” continues its normal The “parent thread” continues its normal execution after creating the “child thread”execution after creating the “child thread”

Memory is shared by the parent and the child Memory is shared by the parent and the child (the array, the location of the sum)(the array, the location of the sum)

Nothing prevents from the parent doing Nothing prevents from the parent doing something to it while the child is still something to it while the child is still executing which may lead to a wrong executing which may lead to a wrong computationcomputation

The bundling and unbundling of arguments is The bundling and unbundling of arguments is a bit tedious, but nothing compared to what’s a bit tedious, but nothing compared to what’s needed with shared memory segments and needed with shared memory segments and processesprocesses

Page 42: Shared-Memory Programming with Threads

pthread_exit()pthread_exit() Terminates the calling threadTerminates the calling thread

#include <pthread.h>#include <pthread.h>void void pthread_exitpthread_exit((

void *retval);void *retval);

The return value is made available to another The return value is made available to another thread calling a thread calling a pthread_join()pthread_join() (see later) (see later)

The previous example had the thread just The previous example had the thread just return from return from function do_work()function do_work()

In this case the call to In this case the call to pthread_exit()pthread_exit() is implicit is implicit The return value of the function serves as the The return value of the function serves as the

argument to the (implicitly called) argument to the (implicitly called) pthread_exit()pthread_exit()..

Page 43: Shared-Memory Programming with Threads

pthread_join()pthread_join() Causes the calling thread to wait for another Causes the calling thread to wait for another

thread to terminatethread to terminate#include <pthread.h>#include <pthread.h>int int pthread_joinpthread_join((

pthread_t thread,pthread_t thread,void **value_ptr);void **value_ptr);

threadthread: input parameter, id of the thread to wait on: input parameter, id of the thread to wait on value_ptrvalue_ptr: output parameter, value given to : output parameter, value given to pthread_exit()pthread_exit() by the terminating thread (which by the terminating thread (which happens to always be a happens to always be a void *void *))

returns 0 to indicate success, error code otherwisereturns 0 to indicate success, error code otherwise multiple simultaneous calls for the same thread are not multiple simultaneous calls for the same thread are not

allowedallowed

Page 44: Shared-Memory Programming with Threads

pthread_kill()pthread_kill() Causes the termination of a threadCauses the termination of a thread

#include <pthread.h>#include <pthread.h>int int pthread_killpthread_kill((

pthread_t thread,pthread_t thread,int sig);int sig);

threadthread: input parameter, id of the thread to : input parameter, id of the thread to terminateterminate

sig:sig: signal number signal number returns 0 to indicate success, error code returns 0 to indicate success, error code

otherwiseotherwise

Page 45: Shared-Memory Programming with Threads

pthread_join() examplepthread_join() exampleint main(void) {int main(void) { long int array[100];long int array[100]; long int sum;long int sum; pthread_t worker_thread;pthread_t worker_thread; struct arguments *arg;struct arguments *arg;

arg = (struct arguments *)calloc(1,sizeof(struct arguments));arg = (struct arguments *)calloc(1,sizeof(struct arguments)); arg->array = array; arg->array = array; arg->size=100; arg->size=100; arg->sum = &sum;arg->sum = &sum;

if (if (pthread_createpthread_create(&worker_thread, NULL, (&worker_thread, NULL, do_work, (void *)arg)) {do_work, (void *)arg)) { fprintf(stderr,”Error while creating thread\n”);fprintf(stderr,”Error while creating thread\n”); exit(1);exit(1); }} ...... if (if (pthread_joinpthread_join(worker_thread, NULL)) {(worker_thread, NULL)) { fprintf(stderr,”Error while waiting for thread\n”);fprintf(stderr,”Error while waiting for thread\n”); exit(1);exit(1); }}}}

Page 46: Shared-Memory Programming with Threads

Synchronizing pthreadsSynchronizing pthreads As we’ve seen earlier, we need a system to As we’ve seen earlier, we need a system to

implement locks to create mutual exclusion implement locks to create mutual exclusion for variable access, via critical sectionsfor variable access, via critical sections

Lock creationLock creation

int int pthread_mutex_initpthread_mutex_init((

pthread_mutex_t *mutex,pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); const pthread_mutexattr_t *attr);

returns 0 on success, an error code otherwisereturns 0 on success, an error code otherwise mutexmutex: output parameter, lock: output parameter, lock attrattr: input, lock attributes: input, lock attributes

NULL: defaultNULL: default There are functions to set the attribute (look at the There are functions to set the attribute (look at the

man pages if you’re interested)man pages if you’re interested)

Page 47: Shared-Memory Programming with Threads

Synchronizing pthreadsSynchronizing pthreads Locking a lockLocking a lock

If the lock is already locked, then the calling thread is If the lock is already locked, then the calling thread is blockedblocked

If the lock is not locked, the the calling thread acquires itIf the lock is not locked, the the calling thread acquires it

int int pthread_mutex_lockpthread_mutex_lock((

pthread_mutex_t *mutex);pthread_mutex_t *mutex);

returns 0 on success, an error code otherwisereturns 0 on success, an error code otherwise mutexmutex: input parameter, lock: input parameter, lock

Just checkingJust checking Returns instead of lockingReturns instead of locking

int int pthread_mutex_trylockpthread_mutex_trylock(( pthread_mutex_t *mutex);pthread_mutex_t *mutex);

returns 0 on success, EBUSY is the lock is locked, an error returns 0 on success, EBUSY is the lock is locked, an error code otherwisecode otherwise

mutexmutex: input parameter, lock: input parameter, lock

Page 48: Shared-Memory Programming with Threads

Synchronizing pthreadsSynchronizing pthreads

Releasing a lockReleasing a lock

int int pthread_mutex_unlockpthread_mutex_unlock((

pthread_mutex_t *mutex);pthread_mutex_t *mutex);

returns 0 on success, an error code returns 0 on success, an error code otherwiseotherwise

mutexmutex: input parameter, lock: input parameter, lock

With locking, trylocking, and unlocking, With locking, trylocking, and unlocking, one can avoid all race conditions and one can avoid all race conditions and protect access to shared variablesprotect access to shared variables

Page 49: Shared-Memory Programming with Threads

Mutex Example:Mutex Example:......pthread_mutex_t mutex;pthread_mutex_t mutex;pthread_mutex_initpthread_mutex_init(&mutex, NULL);(&mutex, NULL);......pthread_mutex_lock(&mutex);pthread_mutex_lock(&mutex);count++;count++;pthread_mutex_unlock(&mutex);pthread_mutex_unlock(&mutex);

Critical Section

To “lock” variable count, just put a To “lock” variable count, just put a pthread_mutex_lock() and pthread_mutex_lock() and pthread_mutex_unlock() around all sections of pthread_mutex_unlock() around all sections of the code that write to variable countthe code that write to variable count

Again, you’re really locking code, not Again, you’re really locking code, not variablesvariables

Page 50: Shared-Memory Programming with Threads

Cleaning up memoryCleaning up memory

Releasing memory for a mutex Releasing memory for a mutex attributeattribute

int int pthread_mutex_destroypthread_mutex_destroy(( pthread_mutex_t *mutex);pthread_mutex_t *mutex);

Releasing memory for a mutexReleasing memory for a mutex

int int pthread_mutexattr_destroypthread_mutexattr_destroy(( pthread_mutexattr_t *mutex);pthread_mutexattr_t *mutex);

Page 51: Shared-Memory Programming with Threads

SignalingSignaling Allows a thread to wait until some process signals Allows a thread to wait until some process signals

that some condition is metthat some condition is met provides a more sophisticated way to synchronize provides a more sophisticated way to synchronize

threads than just mutex locksthreads than just mutex locks Done with “condition variables”Done with “condition variables” Example:Example:

You have to implement a server with a main thread and You have to implement a server with a main thread and many threads that can be assigned work (e.g., an many threads that can be assigned work (e.g., an incoming request)incoming request)

You want to be able to “tell” a thread: “there is work for You want to be able to “tell” a thread: “there is work for you to do”you to do”

Inconvenient to do with mutex locksInconvenient to do with mutex locks the main thread must carefully manage a lock for each worker the main thread must carefully manage a lock for each worker

threadthread everybody must constantly be polling lockseverybody must constantly be polling locks

Page 52: Shared-Memory Programming with Threads

Condition VariablesCondition Variables Condition variables are used in conjunction with Condition variables are used in conjunction with

mutexesmutexes Create a condition variableCreate a condition variable Create an associated mutexCreate an associated mutex

We will see why it’s needed laterWe will see why it’s needed later Waiting on a conditionWaiting on a condition

lock the mutexlock the mutex wait on condition variablewait on condition variable unlock the mutexunlock the mutex

SignalingSignaling Lock the mutexLock the mutex Signal on the condition variableSignal on the condition variable Unlock mutexUnlock mutex

Page 53: Shared-Memory Programming with Threads

pthread_cond_init()pthread_cond_init()

Creating a condition variableCreating a condition variable int int pthread_cond_initpthread_cond_init((

pthread_cond_t *cond,pthread_cond_t *cond, const pthread_condattr_t *attr);const pthread_condattr_t *attr);

returns 0 on success, an error code otherwisereturns 0 on success, an error code otherwise condcond: output parameter, condition: output parameter, condition attrattr: input parameter, attributes (default = NULL): input parameter, attributes (default = NULL)

Page 54: Shared-Memory Programming with Threads

pthread_cond_wait()pthread_cond_wait() Waiting on a condition variableWaiting on a condition variable

int int pthread_cond_waitpthread_cond_wait((

pthread_cond_t *cond,pthread_cond_t *cond, pthread_mutex_t *mutex);pthread_mutex_t *mutex);

returns 0 on success, an error code returns 0 on success, an error code otherwiseotherwise

condcond: input parameter, condition: input parameter, condition mutexmutex: input parameter, associated mutex: input parameter, associated mutex

Page 55: Shared-Memory Programming with Threads

pthread_cond_signal()pthread_cond_signal() Signaling a condition variableSignaling a condition variable

int int pthread_cond_signalpthread_cond_signal((

pthread_cond_t *cond;pthread_cond_t *cond;

returns 0 on success, an error code returns 0 on success, an error code otherwiseotherwise

condcond: input parameter, condition: input parameter, condition

““Wakes up” one thread out of the Wakes up” one thread out of the possibly many threads waiting for possibly many threads waiting for the conditionthe condition The thread is chosen non-The thread is chosen non-

deterministicallydeterministically

Page 56: Shared-Memory Programming with Threads

pthread_cond_broadcast(pthread_cond_broadcast())

Signaling a condition variableSignaling a condition variable int int pthread_cond_broadcastpthread_cond_broadcast((

pthread_cond_t *cond;pthread_cond_t *cond;

returns 0 on success, an error code returns 0 on success, an error code otherwiseotherwise

condcond: input parameter, condition: input parameter, condition

““Wakes up” ALL threads waiting Wakes up” ALL threads waiting for the conditionfor the condition

Page 57: Shared-Memory Programming with Threads

Condition Variable: Condition Variable: exampleexample

Say I want to have multiple threads wait until a counter Say I want to have multiple threads wait until a counter reaches a maximum value and be awakened when it happensreaches a maximum value and be awakened when it happens

pthread_mutex_lockpthread_mutex_lock(&lock);(&lock);while (count < MAX_COUNT) {while (count < MAX_COUNT) { pthread_cond_waitpthread_cond_wait(&cond,&lock);(&cond,&lock);} } pthread_mutex_unlockpthread_mutex_unlock(&lock)(&lock)

Locking the lock so that we can read the value of count without Locking the lock so that we can read the value of count without the possibility of a race conditionthe possibility of a race condition

Calling Calling pthread_cond_wait()pthread_cond_wait() in a loop to avoid “spurious wakes in a loop to avoid “spurious wakes ups”ups”

When going to sleep the When going to sleep the pthread_cond_wait()pthread_cond_wait() function function implicitly releases the lockimplicitly releases the lock

When waking up the When waking up the pthread_cond_wait()pthread_cond_wait() function function implicitly implicitly acquires the lockacquires the lock (and may thus sleep) (and may thus sleep)

Unlocking the lock after exiting from the loopUnlocking the lock after exiting from the loop

Page 58: Shared-Memory Programming with Threads

pthread_cond_timed_waitpthread_cond_timed_wait()()

Waiting on a condition variable Waiting on a condition variable with a timeoutwith a timeout int int pthread_cond_timedwaitpthread_cond_timedwait((

pthread_cond_t *cond,pthread_cond_t *cond, pthread_mutex_t *mutex,pthread_mutex_t *mutex, const struct timespec *delay);const struct timespec *delay);

returns 0 on success, an error code returns 0 on success, an error code otherwiseotherwise

condcond: input parameter, condition: input parameter, condition mutexmutex: input parameter, associated mutex: input parameter, associated mutex delay:delay: input parameter, timeout (same input parameter, timeout (same

fields as the one used for gettimeofday)fields as the one used for gettimeofday)

Page 59: Shared-Memory Programming with Threads

PThreads: ConclusionPThreads: Conclusion A popular way to write multi-threaded codeA popular way to write multi-threaded code If you know pthreads, you’ll have no problem If you know pthreads, you’ll have no problem

adapting to other multi-threading techniquesadapting to other multi-threading techniques Condition variables are a bit odd, but very Condition variables are a bit odd, but very

usefuluseful For you project you may want to use pthreadsFor you project you may want to use pthreads

More informationMore information Man pagesMan pages PThread Tutorial: PThread Tutorial:

http://www.llnl.gov/computing/tutorials/pthreads/http://www.llnl.gov/computing/tutorials/pthreads/


Recommended