Threads
- Thread Concepts
- simplify code that deals with asynchronous events by assigning a separate thread to handle each event type
- Threads automatically have access to the same memory address space and file descriptors
- Some problems can be partitioned so that overall program throughput can be improved
- interactive programs can realize improved response time by using multiple threads
- The benefits of a multithreaded programming model can be realized even if your program is running on a uniprocessor
- A thread consists of the information necessary to represent an execution context within a process
- a thread ID that identifies the thread within a process
- a set of register values
- a stack
- a scheduling priority and policy
- a signal mask
- an errno variable
- thread-specific data
- Everything within a process is sharable among the threads in a process
- text of the executable program
- the program’s global and heap memory, the stacks
- the file descriptors
- Thread Identification
- every thread has a thread ID
- the thread ID has significance only within the context of the process to which it belongs
- A thread ID is represented by the pthread_t data type
- Thread Creation
- When a thread is created, there is no guarantee which will run first: the newly created thread or the calling thread
- The memory location pointed to by tidp is set to the thread ID of the newly created thread when pthread_create returns successfully
- pthread functions usually return an error code when they fail. They don’t set errno like the other POSIX functions
- Thread Termination
- If any thread within a process calls exit, _Exit, or _exit, then the entire process terminates
- the default action is to terminate the process, a signal sent to a thread will terminate the entire process
- A single thread can exit in three ways, thereby stopping its flow of control, without terminating the entire process
- The thread can simply return from the start routine. The return value is the thread’s exit code
- The thread can be canceled by another thread in the same process
- The thread can call pthread_exit
- One thread can request that another in the same process be canceled by calling the pthread_cancel function
- However, a thread can elect to ignore or otherwise control how it is canceled
- thread_cancel doesn’t wait for the thread to terminate; it merely makes the request
- A thread can arrange for functions to be called when it exits pthread_cleanup_push
- Makes a call to pthread_exit
- Responds to a cancellation request
- Makes a call to pthread_cleanup_pop with a nonzero execute argument
- Thread Synchronization
- When multiple threads of control share the same memory, we need to make sure that each thread sees a consistent view of its data
- Mutexes
- A mutex is basically a lock that we set (lock) before accessing a shared resource and release (unlock) when we’re done
- we must first initialize it by either setting it to the constant PTHREAD_MUTEX_INITIALIZER (for statically allocated mutexes only) or calling pthread_mutex_init
- To lock a mutex, we call pthread_mutex_lock
- To unlock a mutex, we call pthread_mutex_unlock
- Deadlock Avoidance
- Deadlocks can be avoided by carefully controlling the order in which mutexes are locked
- assume that you have two mutexes, A and B, that you need to lock at the same time. If all threads always lock mutex A before mutex B, no deadlock can occur from the use of the two mutexes
- pthread_mutex_timedlock
- The timeout specifies how long we are willing to wait in terms of absolute time (as opposed to relative time; we specify that we are willing to block until time X instead of saying that we are willing to block for Y seconds)
- Reader–writer locks
- Only one thread at a time can hold a reader–writer lock in write mode, but multiple threads can hold a reader–writer lock in read mode at the same time
- Reader–writer locks are well suited for situations in which data structures are read more often than they are modified
- Reader–Writer Locking with Timeouts
- pthread_rwlock_timedwrlock
- Condition Variables
- When used with mutexes, condition variables allow threads to wait in a race-free way for arbitrary conditions to occur
- Spin Locks
- the process is blocked by busy-waiting (spinning) until the lock can be acquired
- A spin lock could be used in situations where locks are held for short periods of times and threads don’t want to incur the cost of being descheduled
- Many mutex implementations are so efficient that the performance of applications using mutex locks is equivalent to their performance if they had used spin locks
- The interfaces for spin locks are similar to those for mutexes, making it relatively easy to replace one with the other
- if a spin lock is currently unlocked, then the pthread_spin_lock function can lock it without spinning. If the thread already has it locked, the results are undefined. The call to pthread_spin_lock could fail with the EDEADLK error (or some other error), or the call could spin indefinitely. The behavior depends on the implementation. If we try to unlock a spin lock that is not locked, the results are also undefined
- Barriers
- Barriers are a synchronization mechanism that can be used to coordinate multiple threads working in parallel
- A barrier allows each thread to wait until all cooperating threads have reached the same point, and then continue executing from there