Thread and Process in C++

Introduction

In this post, I discuss about the conceptual aspect of processes and threads: what they are, how the memory layout is for threads, and process. For each aspects, I draw some comparisons between process and threads. No code will be demonstration.

Definition

Process

  • a process is an abstract entity, defined by the kernel, to which system
    resources are allocated in order to execute a program.
  • a process consists of user-space memory containing program code and variables used by that code, and a range of kernel data structures that maintain information about the state of the process.
  • each process has a parent process. Process Id=1, is the main process, the ancestor of all processes, or `init`. If a child process is orphaned, because its parent process terminates, then the child process becomes process 1 or daemon.
    • A daemon runs at system startups, and runs until the system is shut down.
    • A daemon runs in the background and has no controlling terminal. The lack of a controlling terminal ensures that the kernel never automatically generates any job-control or terminal-related signals (such as SIGINT, SIGTSTP, and SIGHUP) for a daemon.
  • 97% of time, the parent process is prioritized by Linux.

Threads

  • A thread is sub-section of a process. A process can contain multiple threads which are running on its stack.
  • When a new thread is created from its main thread, CPU may run threads in any order. A program has no guarantees about which thread will next be scheduled to use the CPU or according to specified synchronization techniques.

Memory Concern

Process: each process has a virtual memory layout map as following

Threads: the following illustrate a virtual memory address of a single process, including multiple threads:

  • when thread objects are created, they are pushed to stack as similar to local variables being pushed to stacked.
  • Each thread has its stack memory, for example, 1 MB in most 32 bit processes with a flat architecture, 4GB limit in the available address space.
  • If too many threads are created, then heap space, uninitialized data, initialized data, code are exhaused.
  • Threads share the same address space including heap, shared libraries, shared memory, ... thus and all access each other 's data.
ProcessThreads
Virtual Memory Management* Child process obtains copies of the parent's stack, data, heap, and text segment.* A single process can have multiple threads
* Threads share the same heaps, intialized, unitialized data and heap segment, shared libs, shared mem.
Direct Memory Access between processesOne process can't read or modify the memory of another process* Threads can directly access and share information with other threads.
* If a thread is joinable, that when it terminates, another thread
can obtain its return status.
Communication between processvia Inter-process communication methods allow transferring information between processesthreads can return result to caller thread via std::promise, std::future.
Advantages* the program
loads and runs faster than single process
* since each process uses
less RAM, more processes can simultaneously be held in RAM.
Threads creation is much faster then process creation.
Disadvantages* If multiple processes are allowed to access the same resource, race condition occurs.
* Failing in one threads can affect all threads.
* Each thread compete for finite memory in the host process.
* When a thread is joined, detached, (terminate), there is not yet guideline on how to deal with local memory allocated by the thread. (no thread destructor) [1]

When not to use concurrency

The following are considerations when using concurrency (with processes or threads), as suggested by [2]

  • Code development and maintenance complexity.
  • The performance gain might not be as large as expected, espectially when the actual time taken by the task is less then the overhead of launching new threads/processes.
  • Threads are limited resouces. Each thread requires a separate stack space. If too many threads are created, then heap space, uninitialized data, initialized data, code are exhaused.
  • The more threads we have, the more context switching the operation system has to do.

References:

[1] Item 37, Effective Modern C++. A way to retify the issue is to implement a ThreadRAII class that provide access to thread object as well as destructor.

[2] Section 1.2.3 , Cplusplus Concurrency In Action.

Leave a Reply

Your email address will not be published. Required fields are marked *