3 min readJun 10, 2024


Why Multi-threading: Multi-threading was introduced to improve throughput, and responsiveness and to utilize multiple resources concurrently.

A thread is the smallest unit of processing that an operating system can schedule. It shares the same memory space with other threads within the same process. A thread is an independent flow of control that operates within the same address space as other independent flows of controls within a process.

In traditional single-threaded process systems, a process has a set of properties. In multithreaded systems, these properties are divided between processes and threads. Each thread is a scheduled entity with properties: stack, scheduling properties, set of pending and blocked signals, and thread specific data. Threads are well-suited entities for modular programming. Threads provide simple data sharing (all threads within a process share the same address space) and powerful synchronization facilities, such as mutexes (mutual exclusion locks) and condition variables.

When a process is created, one thread is automatically created. This thread is called the initial thread. This initial thread executes the main routine.

The following software models can be implemented with threads:

  • Controller/worker model: In the controller/worker model, a controller entity receives one or more requests, and then creates worker entities to execute them. The controller controls the number of workers and what each worker does. A worker runs independently of other workers.
  • Divide and conquer model: In the divide-and-conquer (sometimes called simultaneous computation or work crew) model, one or more entities perform the same tasks in parallel. There is no master entity; all entities run in parallel independently.
  • Producer/consumer model: The producer/consumer (sometimes called pipelining) model is typified by a production line. For example, a reader entity reads raw data from standard input and passes it to the processor entity, which processes the data and passes it to the writer entity, which writes it to standard output. Parallel programming allows the activities to be performed concurrently. In network packet processing, one entity receives the data passes on to the packet processing entity which processes the data.

Thread libraries provide APIs for threads, mutexes, condition variables, etc.

For the creation of threads, we can specify some of the following attributes:

  • detach state attribute: specifies the detached state of the thread. Thread can be created in a detached state or a joinable state.
  • scheduling scope: contention scope of the thread defined by the thread model.
  • scheduling policy: Specifies the scheduling policy of the thread. This scheduling can be FIFO or round-robin scheduling.
  • scheduling priority: specifies the scheduling priority of the thread.
  • Inherit schedule attribute: Specifies how scheduling attributes will be defined either inherited from the creating thread or specified explicitly.
  • Stack attributes: stack size, stack address, guard size (guard area of thread’s stack), etc.

Thread creation in C:

eg. code segment for thread creation:

When calling the pthread_create subroutine, an entry-point routine should be specified. When the thread returns from this routine, the thread is automatically terminated. The entry-point routine has one parameter, a void pointer, specified when calling the pthread_create subroutine. The pthread_create subroutine returns the thread ID of the new thread. The caller can use this thread ID to perform various operations on the thread.

The pthread_self subroutine returns the current thread ID. Its type is pthread_t. pthread_equal subroutine can be used to compare the thread IDs.

Exiting a thread

Calling the pthread_exit subroutine terminates the calling thread. The status parameter is saved and can be used when joining the terminated thread. If the initial thread is terminated, the process gets terminated when the last thread terminates. The pthread_exit subroutine releases any thread-specific data, including the thread’s stack. This subroutine does not clean up the synchronization objects like mutexes, condition variables, and the system resources shared among other threads.