close
    這是我自己讀OPERATING SYSTEM CONCEPTS (6th Edition)的筆記,本來讀的進度很緩慢,直到有一天在網路上看到冼鏡光老師分享上課的slide(OS第7版),唸起OS就愈來有趣啦。
    筆記的章節是依OS第6版整理的,圖片則都是從冼鏡光老師的slide貼上來的,感謝冼老師無私的分享,讓我有機會一窺OS的奧妙。
   
(如有著作權相關問題,請惠予通知)



5. Threads
5.1    Overview
  • A thread, also known as lightweight process (LWP), is a basic unit of CPU execution.
  • A thread is a flow of control within a process. A multithreaded process contains several different flows of control within the same address space.
  • A thread has a thread ID, a program counter, a register set, and a stack. Thus, it is similar to a process has.
  • However, a thread shares with other threads in the same process its code section, data section, and other OS resources (e.g., files and signals).
  • A process, or heavyweight process, has a single thread of control.
         
            5.1.1  Motivation
            5.1.2  Benefits
    • Responsiveness: Other parts (i.e., threads) of a program may still be running even if one part (e.g., a thread) is blocked.
    • Resource Sharing: Threads of a process, by default, share many system resources (e.g., files and memory).
    • Economy: Creating and terminating processes, allocating memory and resources, and context switching processes are very time consuming.
    • Utilization of Multiprocessor Architecture: Multiple CPUs can run multiple threads of the same process. No program change is necessary.
        5.1.3  User and Kernel Threads
    • User Threads:
      • User threads are supported at the user level. The kernel is not aware of user threads.
      • A library provides all support for thread creation, termination, joining, and scheduling.
      • There is no kernel intervention, and, hence, user threads are usually more efficient.
      • Unfortunately, if the kernel is single-threaded, since the kernel only recognized the containing process (of the threads), if one thread is blocked, every other threads of the same process are also blocked because the containing process is blocked.
    • Kernel threads:
      • Kernel threads are directly supported by the kernel (OS). The kernel does thread creation, termination, joining, and scheduling in kernel space.
      • Kernel threads are usually slower than the user threads.
      • However, blocking one thread will not cause other threads of the same process to block. The kernel simply runs other threads.
      • In a multiprocessor environment, the kernel can schedule threads on different processors.
                                 
5.2    Multithreading Models
            5.2.1  Many-to-One Model
    • One kernel thread (or process) has multiple user threads. Thus, this is a user thread model.
    • Thread management is done in user space, so it is efficient, but the entire process will block if a thread makes a blocking system call.
    • Because only one thread can access the kernel at a time, multiple threads are unable to run in parallel on multiprocessors.
                     
            5.2.2  One-to-One Model
    • One user thread maps to on kernel thread (e.g., Linux and Windows).
    • The only drawback to this model is that creating a user thread requires creating the corresponding kernel thread.
                     
                     
            5.2.3  Many-to-Many Model
    • Multiple user threads maps to a number of kernel threads.
                     
5.3    Threading Issues
            5.3.1  The fork and exec System Calls
    • If a thread forks, does the new process:
      • Duplicate all threads?
      • Contain only the forking thread (i.e., single-threaded)?
    • Some systems have two fork system calls, one for each case.
    • If a thread invokes the exec system call, the program specified in the parameter to exec will replace the entire process – including all threads and LWPs.
            5.3.2  Cancellation
    • Thread cancellation means terminating a thread before it has completed. The thread that is to be cancelled is the target thread.
    • There are two types:
      • Asynchronous Cancellation: the target thread terminates immediately.
      • Deferred Cancellation: The target thread can periodically check if it should terminate, allowing the target thread an opportunity to terminate itself in an orderly fashion. The point a thread can terminate itself is a cancellation point.
    • Problem: With asynchoronous cancellation, if the target thread owns some system-wide resources, the system may not be able to reclaim all resources owned by the target thread. 
    • With deferred cancellation, one thread indicating that a target thread is to be cancelled, the target thread determines the time to terminate itself, reclaiming resources is not a problem.
    • Most systems implement asynchromous cancellation for processes (e.g., use the kill system call) and threads.
    • Pthread supports deferred cancellation. 
            5.3.3  Signal Handling
    • Signal is a way the OS uses to notify a process that some event has happened.
    • Once a signal occurs, who is going to handle it? The process, or one of the threads?
    • Synchronous signal: illegal memory access, division by zero.
    • Synchronous signals need to be delivered to the thread that generated the signal and not to other threads in the process.
    • When a signal is generated by an event external to a running process, that process receives the signal asynchronously.
    • Some asynchronous signals – such as a signal that terminates a process (, for example) – should be sent to all threads. Some multithreaded versions of UNIX allow a thread to specify which signals it will accept and which it will block.
    • Every signal has a default signal handler that is run by the kernel when handling the signal. This default action may be overridden by a user-defined signal handler function.
    • Because signals need to be handled only once, typically a signal is delivered only to the first thread found in a process that is not blocking the signal.
    • Handling signals in multithreaded programs:
      • Deliver the signal to the thread to which the signal applies.
      • Deliver the signal to every thread in the process.
      • Deliver the signal to certain threads in the process.
      • Assign a specific thread to receive all signals for the process.
            5.3.4  Thread Pools
    • While we know that managing threads are more efficient than managing processes, creating and terminating threads are still not free.
    • After a process is created, one can immediately create a number of threads and have them waiting.
    • When a new task occurs, one can wake up one of the waiting threads and assign it the work. After this thread completes the task, it goes back to wait.
    • In this way, we save the number of thread creation and termination.
    • These threads are said in a thread pool – create a number of threads at process startup and place them into a pool, where they sit and wait for work.
            5.3.5  Thread-Specific Data
    • Data that a thread needs for its own operation are thread-specific.
    • Poor support for thread-specific data could cause problem. For example, while threads have their own stacks, they share the heap.
    • What if two malloc() or new are executed at the same time requesting for memory from the heap? Or, two printf or cout are run simultaneously?
    • If a library can be used by multiple threads properly, it is a thread-safe one.
5.4    Pthreads (User-level thread library)
  • Pthreads refers to the POSIX standard (IEEE 1003.1c) defining an API for thread creation and synchronization. This is a specification for thread behavior, not an implementation.

/*****************************************************************************************/

#include pthread.h>

#include


int sum;       /* this data is shared by the thread(s) */

void *runner(void *param);     /* the thread */


main(int agrc, char *argv[])

{

           pthread_t tid;        /* the thread identifier */

           pthread_attr_t attr;          /* set of thread attributes */

           if (argc != 2) {

                      fprintf(stderr, “usage: a.out \n”);

                     exit();

           }

           if (atoi(argv[1]) < 0) {

                     fprintf(stderr, “%d must be >= 0\n”, atoi(argv[1]));

           }

           /* get the default attributes */

           pthread_attr_init(&attr);

           /* create the thread */

           pthread_create(&tid, &attr, runner, argv[1]);

           /* now wait for the thread to exit */

           pthread_join(tid, NULL);

           printf(“sum = %d\n”, sum);

}

/* The thread will begin control in this function */

void *runner(void *param)

{

           Int upper = atoi(param);

           Int i;

           sum = 0;

           if (upper > 0) {

                     for (i = 1; i<= upper; i++)

                                sum += i;

           }

           pthread_exit(0);

}

5.5    Solaris 2 Threads (Kernel-thread support)
  • Solaris 2 defines an intermediate level of threads, between user- and kernel-level threads are lightweight processes (LWPs).
  • Each process contains at least one LWP. The thread library multiplexes user-level threads on the pool of LWPs for the process, and only user-level threads currently connected to an LWP accomplish work. The rest are either blocked or waiting for an LWP on which they can run.
  • A user-level thread contains a thread ID; register set (including a program counter and stack pointer); stack; and priority (used by the thread library for scheduling purposes). None of these data structures are kernel resources; all exist within user space.
  • An LWP has a register set for the user-level thread it is running, as well as memory and accounting information. An LWP is a kernel data structure, and it resides in kernel space.
  • A kernel thread has only a small data structure and a stack. The data structure includes a copy of the kernel registers, a pointer to the LWP to which it is attached, and priority and scheduling information.
5.6    Window 2000 Threads (Kernel-thread support)
  • The primary data structures of a thread include:
    • ETHREAD (executive thread block)
    • KTHREAD (kernel thread block)
    • TEB (thread environment block)
5.7    Linux Threads
  • Linux provides a fork system call with the traditional functionality of duplicating a process.
  • Linux also provides the clone system call that is analogous to creating a thread. Clone behaves much like fork, except that instead of creating a copy of the calling process, it creates a separate process that shares the address space of the calling process. It is through this sharing of the address space of the parent process that a cloned task behaves much like a separate thread.
  • When fork is invoked, a new process is created along with a copy of all the associated data structures of the parent process.
  • When the clone system call is made, a new process is created. However, rather than copying all data structures, the new process points to the data structures of the parent process, thereby allowing the child process to share the memory and other process resources of the parent.
  • A set of flags is passed as a parameter to the clone system call. This set of flags is used to indicate how much of the parent process is to be shared with the child (0 ~ 5).
  • Linux does not distinguish between processes and threads, Linux generally uses the term task – rather than process or thread – when referring to a flow of control within a program.
  • Aside from the cloned process, Linux does not support multithreading, separate data structure, or kernel routines.
5.8    Java Threads
  • Java is one of a small number of languages that provide support at the language level for the creation and management of threads.
  • Threads are managed by the Java Virtual Machine, not by a user-level library or kernel, it is difficult to classify Java threads as either user- or kernel-level.
  • All Java programs comprise at least a single thread of control.
            5.8.1  Thread Creation
    • One way to create a thread explicitly is to create a new class that is derived from the Thread class, and to override the run method of the Thread class.
            5.8.2  The JVM and the Host Operating System
    • The specification of the JVM does not indicate how Java threads are to be mapped to the underlying operating system, instead leaving that decision to the particular implementation of the JVM.


arrow
arrow
    全站熱搜

    nix 發表在 痞客邦 留言(0) 人氣()