linux thread

1.1.1 Process

In the early days, people are writing programs for a specific machine, and computing tasks (task) on which to run. Gradually it was discovered that the speed between the CPU and IO devices big change, often are idle CPU is not the CPU can do other things happen in free time? Thus, there is a multi-task (each task is a process), with resource scheduling, with the operating system ...

The process is the smallest unit of resource management, the operating system is divided in a unit process in the allocation of resources (memory, files, etc.). In the era of single CPU (single-core) by scheduling multiple processes (allocation of CPU time slice), we can already listen to music while playing games!

Before the process is described as the smallest unit of resource allocation and scheduling of the execution, but now do not say so, because of the introduction of the concept of threads. Anyway, these are just a name only, in essence, is to look at how resources are allocated and managed.

This article does not discuss the process of scheduling algorithms, such as FCFS, SJF, round-robin like. Here, look at the specific data structure of Linux processes, as well as state transitions:

  • Process data structure

linux process linked list is a two-terminal structure, which mainly includes code segments, data segments, heap, stack, and other memory map table

  • State conversion process

The main process in the ready state, execution, wait, every time switching accompanied by a context switch.

  • Context switching

    Included in the context of the process of execution, the value of the status of all CPU registers, the contents of process and process stack. The so-called handover process that is a process to get lost or CPU time slice, the process by the kernel is responsible for saving a snapshot of the state of the process (context), thereby generating a context switch. We can see the process itself needs to consume a lot of CPU time slice.

Summary: While by multi-process scheduling, processing tasks can be complicated, but you can see the process of switching very frequently. A process just got on another CPU resources may occur due to obstruction of the IO into a wait state. After obtaining a process CPU time slice how to make it do? So we introduced the concept of threads.

1.1.2 Thread

To maximize the efficiency of the use of CPU, IO operation to prevent clogging the entire process runs, the process of reducing the overhead of context switching, so he introduced the concept of threads, the thread as a basic unit of CPU scheduling execution. If a process contains multiple threads, multiple threads that can be executed in parallel or concurrently, and the thread will not lead to blocking process (or ideally theoretical terms).

Why thread can reduce the cost of it? The above process memory control block diagram, the process data structure shared by all threads of the process, in addition to the image program counter thread private, stack space, register. System call handover does not occur between the threads of a process, and multithreading can make better use multiprocessor parallel computing, and so is more convenient direct communication threads.

Although the thread has a lot of advantages, but are conceptual only. Not all operating systems support threads. windows native support for the implementation of the thread, but linux and there is no concept of threads, it is only through multi-threaded outside the kernel, according to the thread support is outside the core, or kernel, the thread is divided into kernel threads and user-level threads.

1.1.3 Posix standard thread

Before speaking under Linux thread implementation, it is necessary to introduce the posix standard thread. POSIX (Portable Operating System Interface) interface (API) is a set of specifications, there is described in C language, code written in between followed posix posix API specification are portable platforms, the JVM used on linux system as the underlying thread library is pthread achieve. On which thread API is called pthread, the standard defines create from threads, communication, quit all relevant API (to pthread_begin with) and behavioral constraints.

The main API:

Prefix Functions Features
pthread_ Thread itself and related functions
pthread_attr_ Thread attributes object
pthread_mutex_ Mutex
pthread_mutexattr_ Mutex attribute object
pthread_cond_ Condition variable
pthread_condattr_ Condition variable attributes object
pthread_key_ Thread private data
pthread_rwlock_ Read-Write Lock
pthread_rwlockattr_ Read-write lock attributes object
pthread_barrier_ barrier
pthread_barrierattr_ Barrier properties of the object
pthread_spin_ Spinlocks

The introduction of the use of header files #include <pthread.h>:

//--------------------线程相关API--------------------//

/** 创建线程 */
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine)(void*), void *arg);
/** 等待线程结束 */
int pthread_join (pthread_t thread, void**value_ptr);
/** 退出线程 */
void pthread_exit(void *value_ptr);
/** 脱离线程: 将线程属性的分离状态设置为 detached,等待结束时回收资源 */
int pthread_detach (pthread_t thread);
/** 结束线程: 给线程发送中止信号 */
int pthread_kill(pthread_t thread, int sig);
/** 获取线程ID */
pthread_t pthread_self(void);

//----------------线程属性相关API-------------------//

/** 设置线程属性,pthread_create会用到 */
int pthread_attr_init(pthread_attr_t *attr);
/** 销毁线程属性 */
int pthread_attr_destroy(pthread_attr_t *attr);

//----------------互斥锁相关API--------------------//

/** 初始化互斥锁对象 */
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
/** 销毁互斥锁对象 */
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
/** 获取互斥锁(阻塞方式) */
int pthread_mutex_lock(pthread_mutex_t *mutex);
/** 获取互斥锁(非阻塞方式) */
int pthread_mutex_trylock(pthread_mutex_t *mutex);
/** 释放互斥锁 */
int pthread_mutex_unlock(pthread_mutex_t *mutex);

//----------------条件变量相关API------------------//

/** 初始化条件变量 */
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
/** 销毁条件变量 */
int pthread_cond_destroy(pthread_cond_t *cond);
/** 在条件变量上阻塞等待 */
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
/** 在条件变量上有时限等待 */
int pthread_cond_timedwait(pthread_cond_t *cond, 
    pthread_mutex_t *mutex, const struct timespec *abstime);
/** 唤醒一个在条件变量上等待的线程 */
int pthread_cond_signal(pthread_cond_t *cond);
/** 唤醒全部在条件变量上等待的线程 */
int pthread_cond_broadcast(pthread_cond_t *cond);

//----------------线程私有数据相关API------------------//

/** 设置线程私有数据 */
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
/** 删除线程私有数据 */
int pthread_key_delete(pthread_key_t key);

//----------------读写锁相关API------------------//

/** 初始化一个读写锁 */
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
/** 销毁读写锁 */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
/** 读锁定(阻塞) */
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
/** 读锁定(非阻塞) */
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
/** 写锁定(阻塞) */
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
/** 写锁定(非阻塞) */
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
/** 释放读写锁 */
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

//----------------屏障相关API------------------//

/** 初始化一个屏障(栅栏) */
int pthread_barrier_init(pthread_barrier_t *barrier,const pthread_barrierattr_t *attr,        unsigned count);
/** 销毁屏障 */
int pthread_barrier_destroy(pthread_barrier_t *barrier);
/** 在屏障上等待 */
int pthread_barrier_wait(pthread_barrier_t *barrier);
复制代码

Here are just some of the API, more API can use the man command to view the manual, are familiar with pthreads api understanding of java threading mechanism is also helpful.

1.1.4 Linux threading support

Linux does not implement kernel-level threads, we can only achieve multithreading capabilities at the user level. Relatively well-known early LinuxThreads, later NGPT and NPTL. These implementations have taken advantage of lightweight processes function Linux.

Lightweight process (LWP) is a copy of a process (clone () system call), but when making a copy, you can selectively copy only partially, clone calls the underlying kernel do_forkmethods:

int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, 	unsigned long stack_size)
复制代码

clone_flags is to copy content such as LinuxThreads when creating a thread, using CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHANDthe specified copy process memory space, file directory, open the file table, signal processors, note that a copy of this new process are shown in task_structthe relevant part of the address will be set up with the the original process corresponding to the same address, in fact, share the same memory, this process is relatively common consumption will be lower. You can see very similar lightweight processes and threads, shared memory space process, a list of open files, signals, etc., also have their own private registers, stack space, but this is not the equivalent of lightweight processes and threads.

  • LinuxThreads

    LinuxThreads to create a lightweight process by creating a thread, the thread model that is one to one, so that there is a thread scheduling os responsible for the management and LinuxThreads by a thread (user level) to manage as thread cancellation, synchronization between threads work. In this way, the definition of a simulation process includes a set of threads, but that is simulated, there must be a lot of problems, such as thread management increased overhead of thread creation, the number of threads by os process limit (later improved version of linux) can not take advantage of SMP, communication needs by way of semaphores, etc., as well as incompatibility issues between threads and posix serious, precisely because of various problems, there are some other new thread library implementation.

  • NGPT

    NGPT (Next-Generation POSIX Threads) was developed by IBM to replace a new LinuxThreads threading library, but has not been widely used, now no longer maintained.

  • NPTL

    NPTL (Native POSIX Thread Library) was developed by Red Hat to replace another set for LinuxThreads threading library. NPTL thread management is not in use, use the kernel supports processes share signal and a signal processor, achieved through the shared memory futex functions do thread synchronization, and can take advantage of SMP characteristics, in theory, improve the performance of multi-threaded, there is an important the point, basic support posix standard.

    Now most of the platform threading library is NPTL, can getconf GNU_LIBPTHREAD_VERSIONview the command.

Summary: Because Linux does not support native semantics of threads, so the threads are used in the linux platform lightweight process to achieve the thread is in this way that is outside the core are also involved in the nucleus, in the nucleus by lightweight process simulation realize semantic thread (thread group, thread communication) in the outer nuclear called "hybrid thread implementation" in some places. All in all, we can know that a thread is a lightweight process in linux platform.

Cipian multithreaded java series of articles for the first chapter, more concerned about future updates

Guess you like

Origin juejin.im/post/5dcde0746fb9a0201f0a9dd8