- sequential programming, VLIW concept, desire to emulate the real world with parallel threads, free-of-charge exploitation of multiple cores (eight per
mythmachine, eight perricemachine), pros and cons of **thread**ing versus **fork**ing. - C++ **
thread**s,threadconstruction using function pointers, blocks, functors,join,detach, race conditions,mutex, IA32 implementation oflockandunlock, spin-lock, busy waiting, preemptive versus cooperative multithreading,yield,**sleep****_for**. - condition variables, rendezvous and thread communication,
**lock_guard**,wait,notify_one,notify_all, deadlock, busy waiting. - semaphore concept and
**s****emaphore**implementation, generalized counter, pros and cons ofsemaphoreversus exposed condition variables, thread pools, cost of threads versus processes. - active threads, blocked threads, ready thread queue, high-level implementation details of the thread manager,
mutex, andcondition_variable_any. - pure C alternatives via **
pthread**s, pros of **pthread**s over C++ thread package.
Logical control flows are concurrent if they overlap in time. This general phenomenon, known as concurrency, shows up at many different levels of a computer system. Hardware exception handlers, processes, and Linux signal handlers are all familiar examples.
Modern operating systems provide three basic approaches for building concurrent programs:
- Processes
- I/O multiplexing
- Threads
Concurrent Programming with Processes
Multiprocessing overview
Program: code you write to execute tasks
Process: an instance of your program running; consists of program and execution state. Each process has a unique PID.
Multiprocessing : multiple processes can run the same program
fork() creates a clone of the current process, and they run concurrently
|
|
- parent (original) process forks off a child (new) process
- The child starts execution on the next program instruction. The parent continues execution with the next program instruction. The order in which process will execute from now on is up to the OS! Nondeterministic ordering of execution across processes, but a parent can wait for its children to terminate using waitpid().
- fork() is called once, but returns twice.
- In the parent, fork() will return the PID of the child (only way for parent to get child’s PID)
- In the child, fork() will return 0 (this is not the child’s PID, it’s just 0)
- if fork() returns < 0, that means an error occurred
- A process can use getppid() to get the PID of its parent, getpid() returns the PID of the current process.
- Everything is duplicated in the child process
- File descriptor table (increasing reference counts on open file table entries)
- Mapped memory regions (the address space)
- Regions like stack, heap, etc. are copied
The parent process’ file descriptor table is cloned on fork and the reference counts within the relevant open file table entries are incremented. This explains how the child can still output to the same terminal!
|
|
|
|
How can the parent and child use the same address to store different data?
- Each program thinks it is given all memory addresses to use
- The operating system maps these virtual addresses to physical addresses
- When a process forks, its virtual address space stays the same
- The operating system will map the child’s virtual addresses to different physical addresses than for the parent
Isn’t it expensive to make copies of all memory when forking?
- The operating system only lazily makes copies.
- It will have them share physical addresses until one of them changes its memory contents to be different than the other.
- This is called copy on write (only make copies when they are written to).
waitpid() is a function that a parent can call to wait for its child to exit.
|
|
- pid: the PID of the child to wait on
- status: where to put info about the child’s termination (or NULL)
- options: optional flags to customize behavior (always 0 for now)
- the function returns when the specified child process exits
- the return value is the PID of the child that exited, or -1 on error (e.g. no child to wait on)
- If the child process has already exited, this returns immediately - otherwise, it blocks
- We can use WIFEXITED and WEXITSTATUS (among others) to extract info from the status.
|
|
Debugging Multiprocess Programs
How do I debug two processes at once? **gdb** has built-in support for debugging multiple processes
-
1set detach-on-fork off- This tells
**gdb**to capture anyfork’d processes, though it pauses them upon the**fork**.
- This tells
-
1info inferiors- This lists the processes that
**gdb**has captured.
- This lists the processes that
-
1inferior X- Switch to a different process to debug it.
-
1detach inferior X- Tell
**gdb**to stop watching the process, and continue it
- Tell
examples:
|
|
Analysis fork()
|
|
|
|
Inter-process communications
- The waitpid function and signals are primitive IPC mechanisms that allow processes to send tiny messages to processes running on the same host.
- The sockets interface is an important form of IPC that allows processes on different hosts to exchange arbitrary byte streams.
- Examples include pipes, FIFOs, System V shared memory, and System V semaphores.
Signals
Race Conditions
Pros and Cons of Processes
- Processes have a clean model for sharing state information between parents and children: file tables are shared and user address spaces are not.
- It is impossible for one process to accidentally overwrite the virtual memory of another process, which eliminates a lot of confusing failures-an obvious advantage.
- Separate address spaces make it more difficult for processes to share state information. To share information, they must use explicit IPC (interprocess communications) mechanisms.
- Another disadvantage of process-based designs is that they tend to be slower because the overhead for process control and IPC is high.
A Concurrent Server Based on Processes


After accepting the connection request, the server forks a child, which gets a complete copy of the server’s descriptor table. The child closes its copy of Listening descriptor 3 , and the parent closes its copy of connected descriptor 4, since they are no longer needed.


|
|
|
|
|
|
|
|
Concurrent Programming with I/O Multiplexing
I/O multiplexing is not the only way to write an event-driven program. Event-driven programs also can be based on threads.
Pros and Cons of 1/0 Multiplexing
Concurrent Programming with Threads
Pros and Cons of 1/0 Threads
Reference
-
https://web.stanford.edu/class/archive/cs/cs110/cs110.1202/static/lectures/
-
https://web.stanford.edu/class/archive/cs/cs110/cs110.1204/static/lectures/
-
https://web.stanford.edu/class/archive/cs/cs110/cs110.1224/examples/
-
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f22/www/lectures/23-concprog.pdf
-
https://www.cs.cmu.edu/afs/cs/academic/class/15213-s14/www/lectures/
-
https://www.cs.cmu.edu/afs/cs/academic/class/15213-s14/www/lectures/23-concurrent-programming.pdf