Chapter 12 POSIX Threads - PowerPoint PPT Presentation

1 / 43
About This Presentation
Title:

Chapter 12 POSIX Threads

Description:

POSIX threads are often called pthreads because all of the thread functions start with pthread ... Most POSIX functions return zero if successful; otherwise, ... – PowerPoint PPT presentation

Number of Views:116
Avg rating:3.0/5.0
Slides: 44
Provided by: JayT4
Category:
Tags: posix | chapter | posix | threads

less

Transcript and Presenter's Notes

Title: Chapter 12 POSIX Threads


1
Chapter 12POSIX Threads
  • Source Robbins and Robbins, UNIX Systems
    Programming, Prentice Hall, 2003.

2
12.1 12.2 Case Study Processing Data from
Multiple Files
3
Multiple File Processing
  • Imagine that you need to write a program that
    reads data from one or more files, where the
    processing steps upon reading the data are the
    same for each file
  • In a non-threaded approach, a blocking read
    operation on any of the files causes the calling
    process to block until input becomes available
  • Such blocking creates difficulties when a process
    expects input from more then one source, since
    the process has no way of knowing which file
    descriptor will produce the next input
  • The multiple file reading problem commonly
    appears in client/server programming because the
    server expects input from multiple clients
  • Of the various approaches that can be used to
    monitor multiple files, both blocking and
    non-blocking strategies can lead to either
    complicated code or busy waiting
  • One promising approach uses a separate thread to
    handle each file, in effect reducing the problem
    to one of processing a single file
  • Multiple threads can simplify the problem of
    processing multiple files because a dedicated
    thread with relatively simple logic can handle
    the processing of each file
  • Threads also make the overlap of I/O and
    processing transparent to the programmer
  • The next four slides show a program that uses a
    thread approach to solve the problem

4
MultipleFiles Program
// Usage a.out file_name_1 file_name_2
... include ltfcntl.hgt include
ltstdio.hgt include ltunistd.hgt include
ltpthread.hgt define MAX_FILES 5 define
BUFFER_SIZE 80 void processFileTable(int
files, int fileCount) void processFile(void
fileDescriptorPtr) void processData(char
data, int dataSize)
(More on next slide)
5
MultipleFiles Program (continued)
//
int main(int argc, char argv) int
fileTableMAX_FILES int i int
nbrFiles nbrFiles argc - 1 for (i 1 i lt
nbrFiles i) fileTablei - 1
open(argvi, O_RDONLY) if (fileTablei - 1
-1) perror("Failed to open file")
// End for processFileTable(fileTable,
nbrFiles) return 0 // End main
(More on next slide)
6
MultipleFiles Program (continued)
void processFileTable(int files, int fileCount)
int status int i pthread_t
threadTableMAX_FILES for (i 0 i lt
fileCount i) status
pthread_create(threadTable i, NULL,
processFile, (files i)) if (status ! 0)
fprintf(stderr, "Failed to create
thread d\n", i) threadTablei
pthread_self() // Mark failed threads //
End for // End for for (i 0 i lt
fileCount i) if (pthread_equal(pthread
_self(), threadTablei)) // Check failed
threads continue status
pthread_join(threadTablei, NULL) if (status
! 0) fprintf(stderr, "Failed to join
thread d s\n", i, strerror(status)) //
End for return // End processFileTable
(More on next slide)
7
MultipleFiles Program (continued)
//
void processFile(void
fileDescriptorPtr) char bufferBUFFER_SIZE
int inFile ssize_t nbrBytes inFile ((int
)(fileDescriptorPtr)) for ( )
nbrBytes read(inFile, buffer, BUFFER_SIZE)
if (nbrBytes lt 0) break
processData(buffer, nbrBytes) // End
for return NULL // End processFile //

void processData(char data, int
dataSize) write(STDOUT_FILENO, data,
dataSize) // End processData
8
12.3a Basic Thread Functionality
9
Thread Package
  • A thread package usually includes functions for
    thread creation and thread destruction,
    scheduling, and enforcement of mutual exclusion
  • A typical thread package also contains a runtime
    system to manage threads transparently (i.e., the
    user is unaware of the runtime system)
  • When a thread is created, the runtime system
    allocates data structures to hold the thread's
    ID, registers, stack, and program counter value
  • The threads for a process share the entire
    address space of that process
  • They can modify global variables, access open
    file descriptors, and cooperate and interfere
    with each other in many ways
  • POSIX threads are often called pthreads because
    all of the thread functions start with pthread
  • POSIX threads are referenced by an ID of type
    pthread_t
  • Most POSIX functions return zero if successful
    otherwise, they return a nonzero error
  • They do not set errno and do not need to be
    restarted if interrupted by a signal
  • The table on the next slide summarizes the basic
    POSIX thread management functions

10
POSIX Thread Functions
Name Description
pthread_attr_init Initialize a thread attribute object
pthread_cancel Terminate another thread
pthread_create Create a thread
pthread_detach Set thread to release resources
pthread_equal Test two thread IDs for equality
pthread_exit Exit a thread without exiting the process
pthread_kill Send a signal to a thread
pthread_join Wait for a thread to terminate
pthread_self Find out own thread ID
11
pthread_attr_init() Function
  • include ltpthread.hgtint pthread_attr_init(pthrea
    d_attr_t attributes)
  • This function initializes a thread attribute
    object with the default settings for each
    attribute as summarized below
  • A thread may be joined by other threads
  • Scheduling parameters, policy, and scope are
    inherited from the creating thread
  • Priority is set to default for the scheduling
    policy as determined by the system
  • The thread is scheduled system wide
  • The stack size is inherited from the process
    stack size attribute
  • If successful, the function returns zero
    otherwise, it returns an error value

12
pthread_self() Function
  • A thread can find out its ID by calling
    pthread_self()include ltpthread.hgtphtread_t
    pthread_self(void)
  • The function returns the thread ID of the calling
    thread
  • No errors are defined for this function

13
pthread_equal() Function
  • Since pthread_t may be a structure, a program
    should use pthread_equal() to compare thread IDs
    for equalityinclude ltpthread.hgtint
    pthread_equal(pthread_t threadA, pthread_t
    threadB)
  • If threadA equals threadB, the function returns a
    nonzero value otherwise, it returns zero
  • No errors are defined for this function
  • Example Usepthread_t currentThreadif (
    pthread_equal( pthread_self(), currentThread) )
    printf("The current thread ID matches my thread
    ID\n")

14
pthread_create() Function
  • The pthread_create() function creates a
    threadinclude ltpthread.hgtint
    pthread_create(pthread_t thread, const
    pthread_attr_t attributes, void
    (start_routine(void ), void argument)
  • The thread parameter points to the ID of the
    newly-created thread
  • The attributes parameter represents an attribute
    object for the thread
  • If attributes is NULL, the new thread has the
    default attributes
  • The start_routine parameter is the name of the
    function that the thread calls when it begins
    execution
  • The function must take a single parameter of type
    void
  • The function must return a pointer of type void
    , which is treated as an exit status The
    argument parameter is the argument passed to the
    start_routine function
  • If successful, the function returns zero
    otherwise, it returns a nonzero error code
  • To pass multiple values as a parameter to a
    thread, a pointer to an array or structure can be
    used
  • Unlike some thread facilities, such as those
    provided by the Java programming language, the
    pthread_create function automatically makes the
    thread runnable without requiring a separate
    start operation

15
Example use of pthread_create()
include ltfcntl.hgt include ltstdio.hgt include
ltunistd.hgt include ltpthread.hgt void
performOperation(void filePtr) int
main(void) int status int inFile pthread_t
threadID inFile open ("sample.dat",
O_RDONLY) // Error checking removed status
pthread_create(threadID, NULL, performOperation,
inFile) if (status ! 0) fprintf(stderr,
"Failed to create thread s\n",
strerror(status)) else fprintf(stderr, "The
thread was created\n") return 0 // End
main //
void performOperation(void filePtr)
// End performOperation
16
pthread_detach() Function
  • When a thread exits, it does not release its
    resources unless it is a detached thread
  • The pthread_detach() function sets a thread's
    internal options to specify that storage for the
    thread can be reclaimed when the thread
    exitsinclude ltpthread.hgtint
    pthread_detach(pthread_t thread)
  • The pthread_detach() function has a single
    parameter, thread, the thread ID of the thread to
    be detached
  • If successful, the function returns zero
    otherwise, it returns a nonzero error code
  • Detached threads do not report their status when
    they exit

17
Example use of pthread_detach()
  • This code segment creates and then detaches a
    threadstatus pthread_create(threadID, NULL,
    doTask, dataFile)
  • if (status ! 0) fprintf(stderr, "Failed to
    create thread\n")
  • else
  • status pthread_detach(threadID)
  • if (status ! 0)
  • fprintf(stderr, "Failed to detach
    thread\n")
  • // End else
  • When the function below is called as a thread, it
    detaches itselfvoid performOperation(void
    argument)
  • int i ((int )(arg))
  • status pthread_detach(pthread_self())
  • if (status ! 0) return NULL
  • fprintf(stderr, "Argument d\n", i)
  • // End performOperation

18
pthread_join() Function
  • Threads that are not detached are joinable and do
    not release all of their resources until another
    thread calls pthread_join() for them or the
    entire process exits
  • The pthread_join() function causes the calling
    thread to wait for the specified thread to exit,
    similar to waitpid() at the process
    levelinclude ltpthread.hgtint
    pthread_join(pthread_t thread, void valuePtr)
  • The function suspends the calling thread until
    the target thread, specified by the first
    parameter, terminates
  • The valuePtr parameter provides a location for a
    pointer to the return status that the target
    passes to pthread_exit() or return
  • If valuePtr is NULL, the calling program does not
    retrieve the target thread return status
  • If successful, pthread_join() returns zero
    otherwise, it returns a nonzero error code
  • A nondetached thread's resources are not released
    until another thread calls phtread_join() with
    the ID of the terminating thread as the first
    parameter
  • To prevent memory leaks, long-running programs
    should eventually call either pthread_detach() or
    pthread_join() for every thread

19
Example use of pthread_join()
  • The code segment below illustrates how to
    retrieve the value passed to pthread_exit() by a
    terminating threadint statusint
    exitCodePtrpthread_t threadIDstatus
    pthread_join(threadID, exitCodePtr)if (status
    ! 0) fprintf(stderr, "Failed to join
    thread\n")else fprintf(stderr, "Exit code
    d\n", exitCodePtr)

20
pthread_exit() Function
  • The pthread_exit() function causes the calling
    thread to terminateinclude ltpthread.hgtvoid
    pthread_exit(void valuePtr)
  • The valuePtr value is made available to a
    successful pthread_join()
  • However, the valuePtr in pthread_exit() must
    point to data that exists after the thread exits
  • Consequently, the thread should not use a pointer
    to local data for valuePtr
  • A process can terminate by calling exit()
    directly, by executing return from the main()
    function, or by having one of the other process
    threads call exit()
  • In any of these cases, all threads terminate
  • If the main thread has no work to do after
    creating other threads, it should either block
    until all threads have completed or call
    pthread_exit(NULL)
  • A call to exit() causes the entire process to
    terminate
  • A call to pthread_exit() causes only the calling
    thread to terminate
  • A thread that executes return from its top level
    implicitly calls pthread_exit() with the return
    value (a pointer) serving as the parameter to
    pthread_exit()
  • A process will exit with a return status of zero
    if its last thread calls pthread_exit()

21
12.3b Canceling a Thread
22
pthread_cancel() Function
  • The pthread_cancel() function permits a thread to
    request that another thread be canceledinclude
    ltpthread.hgtvoid pthread_cancel(pthread_t
    targetThread)
  • The targetThread parameter is the thread ID of
    the thread to be cancelled
  • The function does not cause the calling thread to
    block while the cancellation completes
  • Rather, pthread_cancel() returns after making the
    cancellation request
  • If successful, pthread_cancel() returns zero
    otherwise, it returns a nonzero error code
  • Threads can force other threads to return through
    the cancellation mechanism
  • The reaction of a thread to a cancellation
    request depends on its state and type

23
pthread_setcancelstate() Function
  • Cancellation can cause difficulties if a thread
    holds resources such as an open file descriptor
    that must be released before exiting
  • The pthread_setcancelstate() function changes the
    cancel-ability state of the calling
    threadinclude ltpthread.hgtint
    pthread_setcancelstate(int state, int
    oldState)
  • The state parameter specifies the new state to
    set
  • The oldState parameter points to an integer for
    holding the previous state
  • If successful, the function returns zero
    otherwise, it returns a nonzero error code
  • If a thread has the PTHREAD_CANCEL_ENABLE state,
    it receives cancellation requests
  • If the thread has the PTHREAD_CANCEL_DISABLE
    state, the cancellation requests are held pending
  • By default, threads have the PTHREAD_CANCEL_ENABLE
    state

24
pthread_setcanceltype() Function
  • There may be points in the execution of a thread
    at which an exit would leave the program in an
    unacceptable state
  • The pthread_setcanceltype() function changes the
    cancel-ability type of a thread as specified by
    its type parameterinclude ltpthread.hgtint
    pthread_setcanceltype(int type, int oldType)
  • The oldType parameter is a pointer to a location
    for saving the previous type
  • If successful, the function returns zero
    otherwise, it returns a nonzero error code
  • The cancellation type allows a thread to control
    the point when it exits in response to a
    cancellation request
  • When its cancellation type is PTHREAD_CANCEL_ASYNC
    HRONOUS, the thread can act on the cancellation
    request at any time
  • When its cancellation type is PTHREAD_CANCEL_DEFER
    RED, the thread acts on cancellation requests
    only at specified cancellation points
  • By default, threads have the PTHREAD_CANCEL_DEFERR
    ED type

25
pthread_testcancel() Function
  • A thread can set a cancellation point at a
    particular place in the code by calling the
    pthread_testcancel() function include
    ltpthread.hgtvoid pthread_testcancel(void)
  • The function has no return value
  • When its cancellation type is PTHREAD_CANCEL_DEFER
    RED, the thread accepts pending cancellation
    requests when it reaches such a cancellation
    point
  • Certain blocking functions, such as read(), are
    automatically treated as cancellation points
  • As a general rule, a function that changes its
    cancellation state or its type should restore the
    value before returning
  • A caller cannot make reliable assumptions about
    the program behavior unless this rule is
    observed

26
Example use of pthread_setcancelstate()
void doTask(char command, int commandSize) void
processTask(void argument) char
bufferBUFFER_SIZE int inFile ssize_t
nbrBytes int status int newState int
oldState inFile ( (int ) arg) for ( )
nbrBytes read(inFile, buffer,
BUFFER_SIZE) if (nbrBytes lt 0) break
status pthread_setcancelstate(PTHREAD_CANCEL_D
ISABLE, oldState) if (status ! 0)
return argument doTask(buffer, nbrBytes)
status pthread_setcancelstate(oldstate,
newstate) if (status ! 0) return
argument // End for return NULL // End
processTask
27
(Added) Case Study Parallel Approach for
Performing A Building Search
28
Building Search Program
  • Imagine that you need to write a program that
    demonstrates the simultaneous search of all
    floors in a building in order to find a person
  • This can be done by assigning a specific thread
    to search each floor
  • After searching a floor, a thread reports back to
    the main thread that it either found the person
    hiding in a certain room on the floor or that
    nobody was found after searching the entire floor
  • As soon as a thread announces that it found the
    person, the main thread sends a request to all
    remaining threads (that are still searching) to
    cancel their search
  • The program begins by reading the command line to
    find out how many floors are in the building
  • The program then picks a random floor and room to
    hide the person it is assumed that only one
    person is hidden in the building
  • The program continues by creating a thread to
    search each floor simultaneously
  • The program ends as soon as the hidden person is
    found

29
Building Search Program
include ltstdio.hgt include ltpthread.hgt include
lttime.hgt define MAX_FLOORS 1000 define
MAX_SIDE_LENGTH 10 define MAX_BUFFER_SIZE
40 define FALSE 0 define TRUE 1 void
hidePerson(int nbrFloors) void
searchBuilding(int nbrFloors) void
searchFloor(void floorPtr) static int
buildingMAX_FLOORSMAX_SIDE_LENGTHMAX_SIDE_LEN
GTH
(More on next slide)
30
Building Search Program
int main(int argc, char argv) int floorCount
0 if (argc ! 2) fprintf(stderr,
"\nUsage a.out floors(1-d)\n", MAX_FLOORS)
return 1 // End if else floorCount
atoi(argv1) srand(time(0)) hidePerson(floorC
ount) searchBuilding(floorCount) return 0
// End main
(More on next slide)
31
Building Search Program
void hidePerson(int nbrFloors) int floor int
row int column int room for (floor 0 floor
lt nbrFloors floor) for (row 0 row lt
MAX_SIDE_LENGTH row) for (column 0
column lt MAX_SIDE_LENGTH column)
buildingfloorrowcolumn FALSE // Pick a
random location to hide the person floor rand()
nbrFloors row rand() MAX_SIDE_LENGTH colum
n rand() MAX_SIDE_LENGTH buildingfloorrow
column TRUE room row 10
column fprintf(stderr, "\n(Hiding location)
Floor d Room d\n\n", floor, room)
// End hidePerson
(More on next slide)
32
Building Search Program
void searchBuilding(int nbrFloors) int
status int floor int i int j pthread_t
threadTablenbrFloors int locationnbrFloors i
nt foundPtr // Create a thread to search each
floor for (floor 0 floor lt nbrFloors
floor) locationfloor floor
status pthread_create(threadTable floor,
NULL, searchFloor,
location floor) if (status ! 0)
fprintf(stderr, "Failed to create thread d
s\n", floor, strerror(status))
return // End if // End for
(More on next slide)
33
Building Search Program
// Check the search results returned by each
thread for (i 0 i lt nbrFloors i)
status pthread_join(threadTablei, (void
)foundPtr) if (status ! 0)
fprintf(stderr, "Failed to join thread d s\n",
i, strerror(status)) else if (! (foundPtr) )
// Check for a false condition
fprintf(stderr, "(Floor d) Nobody was found\n",
i) else if (foundPtr lt 10) //
Adjust for insertion of zero in room number
fprintf(stderr, "(Floor d) Found person in
Room d0d\n", i, i,
foundPtr) else fprintf(stderr,
"(Floor d) Found person in Room dd\n",
i, i, foundPtr) for (j i 1
j lt nbrFloors j) pthread_cancel(thread
Tablej) fprintf(stderr, "\nAll
remaining searches have been canceled\n")
break // End else // End
for return // End searchBuilding
(More on next slide)
34
Building Search Program
//
void searchFloor(void
floorPtr) char bufferMAX_BUFFER_SIZE int
floor int row int column int i int
resultPtr floor ((int )(floorPtr)) for
(i 0 i lt MAX_BUFFER_SIZE i) bufferi
'\0' // Null byte resultPtr (int
)malloc(sizeof(int))
(More on next slide)
35
Building Search Program
// Check each room on the floor for (row 0 row
lt MAX_SIDE_LENGTH row) for (column 0
column lt MAX_SIDE_LENGTH column)
pthread_testcancel() if (buildingfloorrow
column) resultPtr row 10
column return resultPtr // End
if // End for resultPtr FALSE return
resultPtr // End searchFloor
36
Sample Program Output
uxb2 a.out 20 (Hiding location) Floor 14
Room 78 (Floor 0) Nobody was found (Floor 1)
Nobody was found (Floor 2) Nobody was
found (Floor 3) Nobody was found (Floor 4) Nobody
was found (Floor 5) Nobody was found (Floor 6)
Nobody was found (Floor 7) Nobody was
found (Floor 8) Nobody was found (Floor 9) Nobody
was found (Floor 10) Nobody was found (Floor 11)
Nobody was found (Floor 12) Nobody was
found (Floor 13) Nobody was found (Floor 14)
Found person in Room 1478 All remaining searches
have been canceled uxb2
37
12.4 Thread Safety
38
Thread Safety
  • A hidden problem with threads is that they may
    call library functions that are not thread-safe,
    possibly producing spurious results
  • A function is thread-safe if multiple threads can
    execute simultaneous active invocations of the
    function without interference
  • POSIX specifies that all the required functions,
    including the functions from the standard C
    library, be implemented in a thread-safe manner
  • There are certain exceptions to this requirement
    some are listed below
  • asctime(), ctime(), getenv(), localtime(),
    rand(), readdir(), setenv(), strerror(), strtok()
  • In traditional UNIX implementations, errno is a
    global external variable that is set when system
    functions produce an error
  • This implementation does not work for
    multithreading, and in most thread
    implementations errno is a macro that returns
    thread-specific information
  • In essence, each thread has a private copy of
    errno
  • The main thread does not have direct access to
    errno for a joined thread, so if needed, this
    information must be returned through the last
    parameter of pthread_join()

39
12.5 User Threads versus Kernel Threads
40
User-Level Threads
  • The two traditional models of thread control are
    user-level threads and kernel-level threads
  • User-level threads usually run on top of an
    existing operating system
  • These threads are invisible to the kernel and
    compete among themselves for the resources
    allocated to their encapsulating process
  • The threads are scheduled by a thread runtime
    system that is part of the process code
  • Programs with user-level threads usually link to
    a special library in which each library function
    is enclosed in a jacket
  • The jacket function calls the thread runtime
    system to do thread management before and
    possibly after calling the jacketed library
    function
  • Functions such as read() and sleep() can present
    a problem for user-level threads because they may
    cause the process to block
  • To avoid blocking the entire process on a
    blocking call, the user-level thread library
    replaces each potentially blocking call in the
    jacket by a nonblocking version

41
User-Level Threads (continued)
  • User-level threads have low overhead, but they
    also have some disadvantages
  • The user-level thread model, which assumes that
    the thread runtime system will eventually regain
    control, can be thwarted by CPU-bound threads
  • A CPU-bound thread rarely performs library calls
    and may prevent the thread runtime system from
    regaining control to schedule other threads
  • The user-level thread model can share only
    processor resources allocated to the
    encapsulating process
  • This restriction limits the amount of available
    parallelism because the threads can run on only
    one processor at a time
  • Since one of the prime motivations of using
    threads is to take advantage of multiprocessor
    workstations, user-level threads alone are not an
    acceptable approach

42
Kernel-level Threads
  • With kernel-level threads, the kernel is aware of
    each thread as a schedulable entity and threads
    compete system-wide for processor resources
  • The scheduling of kernel-level threads can be
    almost as expensive as the scheduling of
    processes themselves, but kernel-level threads
    can take advantage of multiple processors
  • The synchronization and sharing of data for
    kernel-level threads is less expensive than for
    full processes, but kernel-level threads are
    considerably more expensive to manage than
    user-level threads

43
Hybrid Thread Models
  • Hybrid thread models have advantages of both
    user-level and kernel-level models by providing
    two levels of control
  • The programmer writes the program in terms of
    user-level threads and then specifies how many
    kernel-schedulable entities are associated with
    the process
  • The user-level threads are mapped into the
    kernel-schedulable entities at runtime to achieve
    parallelism
  • The level of control that a user has over the
    mapping depends on the implementation
  • For example, in the Sun Solaris thread
    implementation, the user-level threads are called
    threads and the kernel-schedulable entities are
    called lightweight processes
  • The user can specify that a particular thread be
    run by a dedicated lightweight process or that a
    particular group of threads be run by a pool of
    lightweight processes
  • The POSIX thread scheduling model is a hybrid
    model that is flexible enough to support both
    user-level and kernel-level threads in particular
    implementations of the standard
  • The model consists of two levels of scheduling
    threads and kernel entities
  • The threads are analogous to user-level threads
  • The kernel entities are scheduled by the kernel
  • The thread library decides how many kernel
    entities it needs and how they will be mapped

?
Write a Comment
User Comments (0)
About PowerShow.com