COMP 3511: Lecture 10

Date: 2024-10-08 14:53:43

Reviewed:

Topic / Chapter:

summary

❓Questions

Notes

Threads (cont.)
  • Multithreading models (cont.)

  • Multithreading: many-to-one

    • many user thread: mapped to single kernel thread
    • only one user thread mapped to kernel thread at execution time
      • which user thread is mapped: scheduling problem
    • one thread blocking (of thread): causes
      • cases all
    • m
    • no performance benefit
      • still, structure-wise works like multithreading
      • cannot run in parallel on multicore system
        • as one kernel thread: can be active at a time
    • examples
      • Solaris Green Threads
      • GNU Portable Threads
    • πŸ‘¨β€πŸ« used in the past due to resource limitation
      • kernel thread: requires resource
      • user thread: piece of code waiting for execution
    • few systems currently use this model
    • 01_many_to_one
  • Multithreading: one-to-one

    • each user-level thread: maps to one kernel threads
    • maximum concurrency: allows multiple threads to run in parallel
      • having more kernel threads than user threads: meaningless
    • i.e. creation of user thread: mandates kernel thread creation
      • max no. of threads / process: might be restricted due to overhead
      • could have been problematic in the past
        • as kernel thread consumes resources: memory, IO, etc.
    • examples
      • Windows
      • Linux
    • 02_one_to_one
  • Multithreading: many-to-many

    • multiplexing many user=level
    • in-between
    • process-contention scope: to be discussed later (Ch. 5)
      • πŸ‘¨β€πŸ« similar to many-to-one mapping
      • we have scheduling problem
    • 03_many_to_many
  • Multithreading: two-level

    • similar to many-to-many
    • but: it allows user thread to be bound to kernel thread
      • e.g. some user thread: significant, and requires set kernel thread
    • 04_two_level
  • Multithreading mapping models

    • many-to-many: most flexible
    • but difficult ti implement in practice
    • in modern computer: limiting no. of kernel threads: less of a problem
      • thanks to multi core
Threading Issues
  • fork(), exec() semantics

    • does fork() by thread: duplicate only the calling thread?
      • or all threads of a process?
    • some UNIX versions: chosen two versions of fork()
      • if exec() called immediately after forking: duplicate only calling thread
      • exec(): works as normal - replacing the entire process (although only calling thread is copied)
      • πŸ‘¨β€πŸ« 'one' of the improvement case
    • different improvements exist!
  • Signal handling

    • signals: notify a process that a particular event has occurred
      • can be receives synchronously / asynchronously
      • based on source / reason
    • synchronous signals: delivered to same process performing operation causing signal
      • d.g. illegal memory access / division by 0
    • signals: handled in different ways
      • some signals: ignored
      • some: handled by terminating program
        • e.g. illegal memory access
    • signal handler: process signal
      • signal: generated by a particular event
      • delivered to a process
      • handled by one of two signal handlers
        • default vs. user defined
    • every signal: w/ default handler that kernel users
    • where signal shall be delivered for a multi-thread process?
      • deliver: signal to thread to signal applies
      • deliver: signal to every thread in process
      • deliver: signal to certain thread in process
      • assign a specific thread to receive all signals
    • method of delivering signal: depends on signal type
      • synchronous signal: delivered to thread causing the signal (not other threads)
      • asynchronous signals (e.g. termination process): sent to all threads
    • UNIX function for delivering kill signal: send to all thread of the process
      • s
      • specifies pid
    • POSIX Pthread function: allows signal to be delivered to a specified thread
      • specifies tid
    • d
  • Thread cancellation

    • terminating thread before finishing

      • thread to be cancelled: target thread
    • cancellation scenario

      • asynchronous cancellation: terminate target thread immediately
      • deferred cancellation: target thread: periodically check if it should terminate
        • allows termination in orderly fashion
        • e.g. when modifying an inter-process variable / in critical point, target thread shouldn't be terminated
    • invoking thread cancellation: requests cancellation

      • actual cancellation: depending on thread state / type
    • w/ Pthreads:

    • by nature: cancellation of a thread affects other threads within the same process

      modestatetype
      offdisabled
      deferredenableddeferred
      asynchronousenabledasynchronous
      Pthread code for created cancel of a thread
      #include <pthread.h>
      #pthread_t tid
      
      /* create the thread */
      pthread_create(&tid, 0, worker, NULL);
      // worker: a start routine / function call
      
      /* cancel the thread */ 
      pthread_cancel(tid);
      
      /* wait for the thread to terminate */
      pthread_join(tid, NULL);
      
  • OS example: Windows

    • Windows application: runs as a separate process
    • Windows API: primary API for Windows app
    • w/ one-to-one mapping
    • general components of a Window thread
      • tid
      • register set
      • PC
      • separate user / kernel stacks
    • context of a thread: register set, stacks, and private storage areas
    • primary data structures of a thread
      • ethread
      • kthread
      • TEB (thread environment block)
      • 05_windows_thread
  • OS example: Linux

    • Linux: does not differentiate threads & process
      • special kind of process: task
    • thread in Linux: process that (may) share certain resource w/ other thread
      • each thread: w/ unique task_struct and appears as a normal process
      • threads in Linux: happens to share everything (except context)
        • e.g. address space
        • then they behave like threads
      • β­πŸ‘¨β€πŸ« Linux approach: provides much flexibility
        • e.g. sharing program, but not data
        • or sharing data, but program
        • or sharing file, but nothing else
        • impossible with traditional approach
    • contracts greatly w/ Windows / Sun Solaris
      • w/ explicit kernel support for threads / lightweight processes
    • if a process: consist of two threads
      • in Windows
      • in Linux: simply 2 tasks w/ normal task_struct structure
        • that are set up to share resources
    • threads: created just like normal tasks
      • except: clone() syscall used to pass flag
      • clone(): allows a child task to share part of execution context w/ parent
      • clone(): specifies what to share
      • πŸ‘¨β€πŸ« fork / clone: creates a new task
        • clone(): only in Linux
      • flags control behavior
    • instead of copying all data structures
      • new task points to data structures of parent task
    • normal fork(): can be implemented as
      • clone(SIGCHLD, 0);
CPU Scheduling: Basic Concepts
  • Basic concepts

    • objective of multiprogramming: have process running at all time
      • i.e. maximize CPU utilization
    • process execution: made of cycles of CPU execution & IO wait
      • ask CPU burst and IO burst
      • πŸ‘¨β€πŸ« based on what you are doing at the point
      • 06_CPU_IO_burst
    • when CPU idle:
      • OS try to select one process on ready queue & execute
      • unless ready queue is empty = no process in ready state
    • selection of process: done by CPU scheduler
      • aka process scheduler, short-term scheduler
  • History of CPU-burst times

    • majority of CPU burst time: very short
      • but very few CPU extensive jobs exist
      • aka: long-tail distribution
    • typically
      • d
    • distribution: matters when we design a CPU-scheduling algorithm
    • 07_CPU_burst_frequency
  • CPU scheduler

    • CPU scheduler: selects on process thread on ready queue
      • i.e. what to be executed next?
      • queue
    • CPU scheduling: may take place in following 4 conditions (when scheduling must be done)
      1. switching from running -> waiting state (e.g. IO request / wait)
      2. process terminates
        • giving up CPU voluntarily
      3. switching from running to ready state
        • i.e. interrupt
      4. switching from waiting to ready / new to ready
        • e.g. completion of IO
        • new process arrives on ready queue w/ higher priority
          • if it is priority-based scheduling
    • case 1 & 2: non-preemptive
      • giving up CPU voluntarily
    • case 3 & 4: preemptive
      • OS: forces to give up CPU
      • consider access to: shared data
  • Dispatcher

    • dispatcher module: allocates CPU to process selected by scheduler
    • involves:
    • no. of context switches:
      • can be obtained by vmstat on Linux
      • ~= hundred context switches / sec usually
  • Scheduling criteria

    • CPU utilization: fraction of the time that CPU is busy
      • as long as ready queue is not empty: CPU must not be idle
      • πŸ‘¨β€πŸ« priority no matter what scheduler you use
    • throughput: no. of process / job completed per time
    • response time: only matters for robin-round
    • fairness
    • computation of each: will be explained later
    • generally: desirable to optimize all criteria
      • but there might be conflict, which different considerations in practice
    • mostly
    • in practice: we prefer to optimize minimum / maximum values rather than average
      • and there are many things to be considered
    • πŸ‘¨β€πŸ« interactive
      • interactive: CPU
      • non-interactive: does not require sCU attention until termination
        • e.g. ML communication