精华内容
下载资源
问答
  • python线程进程、异步IO

    千人学习 2017-03-06 18:23:52
    该章节主要包括线程进程的概念,基于python的线程进程实现,GIL锁的影响,消费者生产者模型,进程池的应用以及IO模型的介绍,一句话概括本章的内容就是:实现并发编程,即计算机能够同时处理多个任务。
  • 进程-线程-多线程 1、进程(process) 狭义定义:进程就是一段程序的执行过程 简单的来讲进程的概念主要有两点: 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)...

    进程-线程-多线程

    1、进程(process)
    狭义定义:进程就是一段程序的执行过程
    简单的来讲进程的概念主要有两点:
    第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
    第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
    进程状态:进程有三个状态,就绪、运行、阻塞。

    511遇见易语言多线程大漠多线程


    2、线程(thread)
    通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源。
    3、进程与线程的区别:
    每个进程都有私有的虚拟地址空间,进程的所有线程共享同一地址空间。每个线程被CPU分配一个时间片,一旦被激活,它正常运行直到时间片耗尽并被挂起,此时,操作系统选择另一个线程进行运行。
    简而言之,一个进程至少有一个线程.
    线程的划分尺度小于进程,使得多线程程序的并发性高。
    1)线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
    2)一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
    3)进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;
    4)调度和切换:线程上下文切换比进程上下文切换要快得多。
    4、什么是单线程和多线程?
    单线程,顾名思义即是只有一条线程在执行任务
    多线程,创建多条线程同时执行任务
    5、并行和并发的区别,
    并发:交替做不同事的能力
    并行:同时做不同事的能力
    行话解释:
    并发:不同代码块交替执行的性能
    并行:不同代码块同时执行的性能
    6、多线程在多核上是并发还是并行?
    对于单核,多线程的多任务是在单cpu交替执行,属于并发;
    对于多核,多线程的任务如果能够分布在各个cpu,上(线程数少许核心数),那么就是并行。
    7、拓展
    同步和异步 ----- 异步的反义词是同步
    顺序和并发 ----- 并发的反义词是顺序
    串行和并行 ----- 并行的反义词是串行
    简单的说:并行是多线程的一种形式,多线程是并发的一种形式。异步也是并发的一种形式。
    8、线程的生命周期
    9、线程的安全
    10、线程池

    展开全文
  • 进程线程的区别:对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品。而线程,相对于进程而言,是一个更加接近于执行体的概念,可以和同进程的其他线程之间直接共享数据,...

    前言:

    腾讯笔试中多道选择题考到这个问题,这里总结一下。学习Java的童鞋可能对于线程的理解要比学php好很多。本文参考于线程通信与进程通信的区别

    进程和线程的区别:

    对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品。

    而线程,相对于进程而言,是一个更加接近于执行体的概念,可以和同进程的其他线程之间直接共享数据,而且拥有自己的栈空间,拥有独立序列。

    共同点: 它们都能提高程序的并发度,提高程序运行效率和响应时间。线程和进程在使用上各有优缺点。 线程执行开销比较小,但不利于资源的管理和保护,而进程相反。同时,线程适合在SMP机器上运行,而进程可以跨机器迁移。

    他们之间根本区别在于 多进程中每个进程有自己的地址空间,线程则共享地址空间。所有其他区别都是因为这个区别产生的。比如说:
    1. 速度。线程产生的速度快,通讯快,切换快,因为他们处于同一地址空间。
    2. 线程的资源利用率好。
    3. 线程使用公共变量或者内存的时候需要同步机制,但进程不用。

    而他们通信方式的差异也仍然是由于这个根本原因造成的。

    通信方式之间的差异

    因为那个根本原因,实际上只有进程间需要通信,同一进程的线程共享地址空间,没有通信的必要,但要做好同步/互斥,保护共享的全局变量。

    而进程间通信无论是信号,管道pipe还是共享内存都是由操作系统保证的,是系统调用.

    一、进程间的通信方式

    1. 管道( pipe ):
      管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
    2. 有名管道 (namedpipe) :
      有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
    3. 信号量(semophore ) :
      信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
    4. 消息队列( messagequeue ) :
      消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    5. 信号 (sinal ) :
      信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
    6. 共享内存(shared memory ) :
      共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
    7. 套接字(socket ) :
      套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同设备及其间的进程通信。

    二、线程间的通信方式

    1. 锁机制:包括互斥锁、条件变量、读写锁
      • 互斥锁提供了以排他方式防止数据结构被并发修改的方法。
      • 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
      • 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
    2. 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
      信号机制(Signal):类似进程间的信号处理

    线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

    展开全文
  • 多线程切换以及线程进程之间关系

    千次阅读 2017-02-23 09:53:39
    他只拥有进程中一些资源,这次资源对于这个线程来说是必不可少的。而所有的线程共享进程的资源。因此不同的线程之间可以共享一些数据变量。而进程则不可以,因为不同进程有不同过的进程控制块,分别处于不同的屋里...
    进程是资源拥有的单位。线程是调度的最小单位。又称为轻进程。他只拥有进程中一些资源,这次资源对于这个线程来说是必不可少的。而所有的线程共享进程的资源。因此不同的线程之间可以共享一些数据变量。而进程则不可以,因为不同进程有不同过的进程控制块,分别处于不同的屋里地址空间里面。
    


    每个线程都有自己的工作内存,也就是栈,如果从更底层的来说,相当于硬件的高速缓存,进程的一些公共资源常存放在堆中也就是主内存。不同线程之间的内容切换,首先要把各自的数据放到主内存中,才可以互相访问切换。


    传统的操作系统中,没有引入线程,则并发是指进程。而对于进程的并发调度,也就是上下文切换,需要浪费极大地系统资源,例如cpu现场的保护,寄存器,内存地址的信息记录,调度算法的执行,以及进程状态的转换如从运行状态转换到阻塞状态,而且还要把把进程转到相应的队列里面。又因为有些进程只有一部分代码需要别的进程提供一些数据。如果因为这一点的东西需要数据而阻塞,然后要发生强大的进程切换,明显是浪费很多资源。
    为此,在后来的操作系统中引入了线程概念。线程就是把一个进程分成好多部分,每一个部分都是一个线程,这所有的线程,共享进程的资源。当有一个线程需要别的进程提供数据,发生阻塞的时候,只有这个线程发生阻塞,其他的线程或许不需要这些数据也可以运行,因此只需要阻塞这个线程。进行单个线程切换,而整个进程则不需要切换,因此效率更高。单个线程的调度只需要保存一些必要的信息,如寄存器值,栈之子指针内容。线程切换,只需要更改一些寄存器的指针,如PC,pd等寄存器,当然这些是通过硬件实现的,效率是很快的,然后指向当前线程的代码开始地址处,当然对于源代码来说,本质上会经过编译程序和链接程序最终编程目标代码存放在内存之中的某一空白的内存地址处,并同时记录该内存地址的首地址,这些都是硬件级别的调用,只要要硬件的一些寄存器之类的东西转换一下就可以。速度相当快。并不需要什么进程调度算法,这些很慢的调度。因此引入线程,后系统的并发度会更高。




    线程切换过程:
    1.虚拟机启动之后,就进入了解释器的死循环,一直解释执行pc指针对应的java字节码。
    2. 每个现在对应着一个stack,方面调用的时候,会在其上分配栈帧,由sp,fp等指针指向。
    3. 线程调度,其实就是记录下当前线程的pc,sp,fp等指针,并将这几个指针(pc,sp,fp等,都是全局的)指向下一个将要执行的线程的相应位置。
    4. 当恢复上述的几个指针之后,就切换回之前的线程了
    展开全文
  • linux 线程 进程经典文章

    千次阅读 2009-03-04 14:36:00
    linux 线程 进程有关linux下进程线程看过很多文章,我觉的这篇可以说最经典 ---------------------------------一.基础知识:线程进程 按照教科书上的定义,进程是资源管理的...

     

    linux 线程 进程

    有关linux下进程与线程看过很多文章,我觉的这篇可以说经典

    ---------------------------------

    .基础知识:线程和进程

    按照教科书上的定义,进程是资源管理的最小单位,线程是程序执行的最小单位。在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持SMP以及减小(进程/线程)上下文切换开销。

    无论按照怎样的分法,一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等),而将线程分配到某个cpu上执行。一个进程当然可以拥有多个线程,此时,如果进程运行在SMP机器上,它就可以同时使用多个cpu来执行各个线程,达到最大程度的并行,以提高效率;同时,即使是在单cpu的机器上,采用多线程模型来设计程序,正如当年采用多进程模型代替单进程模型一样,使设计更简洁、功能更完备,程序的执行效率也更高,例如采用多个线程响应多个输入,而此时多线程模型所实现的功能实际上也可以用多进程模型来实现,而与后者相比,线程的上下文切换开销就比进程要小多了,从语义上来说,同时响应多个输入这样的功能,实际上就是共享了除cpu以外的所有资源的。

    针对线程模型的两大意义,分别开发出了核心级线程和用户级线程两种线程模型,分类的标准主要是线程的调度者在核内还是在核外。前者更利于并发使用多处理器的资源,而后者则更多考虑的是上下文切换开销。在目前的商用系统中,通常都将两者结合起来使用,既提供核心线程以满足smp系统的需要,也支持用线程库的方式在用户态实现另一套线程机制,此时一个核心线程同时成为多个用户态线程的调度者。正如很多技术一样,"混合"通常都能带来更高的效率,但同时也带来更大的实现难度,出于"简单"的设计思路,Linux从一开始就没有实现混合模型的计划,但它在实现上采用了另一种思路的"混合"

    在线程机制的具体实现上,可以在操作系统内核上实现线程,也可以在核外实现,后者显然要求核内至少实现了进程,而前者则一般要求在核内同时也支持进程。核心级线程模型显然要求前者的支持,而用户级线程模型则不一定基于后者实现。这种差异,正如前所述,是两种分类方式的标准不同带来的。

    当核内既支持进程也支持线程时,就可以实现线程-进程的"多对多"模型,即一个进程的某个线程由核内调度,而同时它也可以作为用户级线程池的调度者,选择合适的用户级线程在其空间中运行。这就是前面提到的"混合"线程模型,既可满足多处理机系统的需要,也可以最大限度的减小调度开销。绝大多数商业操作系统(如Digital UnixSolarisIrix)都采用的这种能够完全实现POSIX1003.1c标准的线程模型。在核外实现的线程又可以分为"一对一""多对一"两种模型,前者用一个核心进程(也许是轻量进程)对应一个线程,将线程调度等同于进程调度,交给核心完成,而后者则完全在核外实现多线程,调度也在用户态完成。后者就是前面提到的单纯的用户级线程模型的实现方式,显然,这种核外的线程调度器实际上只需要完成线程运行栈的切换,调度开销非常小,但同时因为核心信号(无论是同步的还是异步的)都是以进程为单位的,因而无法定位到线程,所以这种实现方式不能用于多处理器系统,而这个需求正变得越来越大,因此,在现实中,纯用户级线程的实现,除算法研究目的以外,几乎已经消失了。

    Linux
    内核只提供了轻量进程的支持,限制了更高效的线程模型的实现,但Linux着重优化了进程的调度开销,一定程度上也弥补了这一缺陷。目前最流行的线程机制LinuxThreads所采用的就是线程-进程"一对一"模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。Linux-LinuxThreads的运行机制正是本文的描述重点。

    .Linux 2.4内核中的轻量进程实现

    最初的进程定义都包含程序、资源及其执行三部分,其中程序通常指代码,资源在操作系统层面上通常包括内存资源、IO资源、信号处理等部分,而程序的执行通常理解为执行上下文,包括对cpu的占用,后来发展为线程。在线程概念出现以前,为了减小进程切换的开销,操作系统设计者逐渐修正进程的概念,逐渐允许将进程所占有的资源从其主体剥离出来,允许某些进程共享一部分资源,例如文件、信号,数据内存,甚至代码,这就发展出轻量进程的概念。Linux内核在2.0.x版本就已经实现了轻量进程,应用程序可以通过一个统一的clone()系统调用接口,用不同的参数指定创建轻量进程还是普通进程。在内核中,clone()调用经过参数传递和解释后会调用do_fork(),这个核内函数同时也是fork()vfork()系统调用的最终实现:



    int do_fork(unsigned long clone_flags, unsigned long stack_start,
    struct pt_regs *regs, unsigned long stack_size)

    其中的clone_flags取自以下宏""值:



    #define CSIGNAL 0x000000ff /* signal mask to be sent at exit */
    #define CLONE_VM 0x00000100 /* set if VM shared between processes */
    #define CLONE_FS 0x00000200 /* set if fs info shared between processes */
    #define CLONE_FILES 0x00000400 /* set if open files shared between processes */
    #define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */
    #define CLONE_PID 0x00001000 /* set if pid shared */
    #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
    #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
    #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */
    #define CLONE_THREAD 0x00010000 /* Same thread group? */
    #define CLONE_NEWNS 0x00020000 /* New namespace group? */
    #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)

    do_fork()中,不同的clone_flags将导致不同的行为,对于LinuxThreads,它使用(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)参数来调用clone()创建"线程",表示共享内存、共享文件系统访问计数、共享文件描述符表,以及共享信号处理方式。本节就针对这几个参数,看看Linux内核是如何实现这些资源的共享的。

    1.CLONE_VM

    do_fork()
    需要调用copy_mm()来设置task_struct中的mmactive_mm项,这两个mm_struct数据与进程所关联的内存空间相对应。如果do_fork()时指定了CLONE_VM开关,copy_mm()将把新的task_struct中的mmactive_mm设置成与current的相同,同时提高该mm_struct的使用者数目(mm_struct::mm_users)。也就是说,轻量级进程与父进程共享内存地址空间,由下图示意可以看出mm_struct在进程中的地位:


    2.CLONE_FS

    task_struct
    中利用fsstruct fs_struct *)记录了进程所在文件系统的根目录和当前目录信息,do_fork()时调用copy_fs()复制了这个结构;而对于轻量级进程则仅增加fs->count计数,与父进程共享相同的fs_struct。也就是说,轻量级进程没有独立的文件系统相关的信息,进程中任何一个线程改变当前目录、根目录等信息都将直接影响到其他线程。

    3.CLONE_FILES

    一个进程可能打开了一些文件,在进程结构task_struct中利用filesstruct files_struct *)来保存进程打开的文件结构(struct file)信息,do_fork()中调用了copy_files()来处理这个进程属性;轻量级进程与父进程是共享该结构的,copy_files()时仅增加files->count计数。这一共享使得任何线程都能访问进程所维护的打开文件,对它们的操作会直接反映到进程中的其他线程。

    4.CLONE_SIGHAND

    每一个Linux进程都可以自行定义对信号的处理方式,在task_struct中的sigstruct signal_struct)中使用一个struct k_sigaction结构的数组来保存这个配置信息,do_fork()中的copy_sighand()负责复制该信息;轻量级进程不进行复制,而仅仅增加signal_struct::count计数,与父进程共享该结构。也就是说,子进程与父进程的信号处理方式完全相同,而且可以相互更改。

    do_fork()
    中所做的工作很多,在此不详细描述。对于SMP系统,所有的进程fork出来后,都被分配到与父进程相同的cpu上,一直到该进程被调度时才会进行cpu选择。

    尽管Linux支持轻量级进程,但并不能说它就支持核心级线程,因为Linux"线程""进程"实际上处于一个调度层次,共享一个进程标识符空间,这种限制使得不可能在Linux上实现完全意义上的POSIX线程机制,因此众多的Linux线程库实现尝试都只能尽可能实现POSIX的绝大部分语义,并在功能上尽可能逼近。

    .LinuxThread的线程机制

    LinuxThreads
    是目前Linux平台上使用最为广泛的线程库,由Xavier Leroy (Xavier.Leroy@inria.fr)负责开发完成,并已绑定在GLIBC中发行。它所实现的就是基于核心轻量级进程的"一对一"线程模型,一个线程实体对应一个核心轻量级进程,而线程之间的管理在核外函数库中实现。

    1.
    线程描述数据结构及实现限制

    LinuxThreads
    定义了一个struct _pthread_descr_struct数据结构来描述线程,并使用全局数组变量__pthread_handles来描述和引用进程所辖线程。在__pthread_handles中的前两项,LinuxThreads定义了两个全局的系统线程:__pthread_initial_thread__pthread_manager_thread,并用__pthread_main_thread表征__pthread_manager_thread的父线程(初始为__pthread_initial_thread)。

    struct _pthread_descr_struct
    是一个双环链表结构,__pthread_manager_thread所在的链表仅包括它一个元素,实际上,__pthread_manager_thread是一个特殊线程,LinuxThreads仅使用了其中的errnop_pidp_priority等三个域。而__pthread_main_thread所在的链则将进程中所有用户线程串在了一起。经过一系列pthread_create()之后形成的__pthread_handles数组将如下图所示:

    2 __pthread_handles数组结构

    新创建的线程将首先在__pthread_handles数组中占据一项,然后通过数据结构中的链指针连入以__pthread_main_thread为首指针的链表中。这个链表的使用在介绍线程的创建和释放的时候将提到。

    LinuxThreads
    遵循POSIX1003.1c标准,其中对线程库的实现进行了一些范围限制,比如进程最大线程数,线程私有数据区大小等等。在LinuxThreads的实现中,基本遵循这些限制,但也进行了一定的改动,改动的趋势是放松或者说扩大这些限制,使编程更加方便。这些限定宏主要集中在sysdeps/unix/sysv/linux/bits/local_lim.h(不同平台使用的文件位置不同)中,包括如下几个:

    每进程的私有数据key数,POSIX定义_POSIX_THREAD_KEYS_MAX128LinuxThreads使用PTHREAD_KEYS_MAX1024;私有数据释放时允许执行的操作数,LinuxThreadsPOSIX一致,定义PTHREAD_DESTRUCTOR_ITERATIONS4每进程的线程数,POSIX定义为64LinuxThreads增大到1024PTHREAD_THREADS_MAX);线程运行栈最小空间大小,POSIX未指定,LinuxThreads使用PTHREAD_STACK_MIN16384(字节)。

    2.
    管理线程

    "
    一对一"模型的好处之一是线程的调度由核心完成了,而其他诸如线程取消、线程间的同步等工作,都是在核外线程库中完成的。在LinuxThreads中,专门为每一个进程构造了一个管理线程,负责处理线程相关的管理工作。当进程第一次调用pthread_create()创建一个线程的时候就会创建(__clone())并启动管理线程。

    在一个进程空间内,管理线程与其他线程之间通过一对"管理管道(manager_pipe[2]"来通讯,该管道在创建管理线程之前创建,在成功启动了管理线程之后,管理管道的读端和写端分别赋给两个全局变量__pthread_manager_reader__pthread_manager_request,之后,每个用户线程都通过__pthread_manager_request向管理线程发请求,但管理线程本身并没有直接使用__pthread_manager_reader,管道的读端(manager_pipe[0])是作为__clone()的参数之一传给管理线程的,管理线程的工作主要就是监听管道读端,并对从中取出的请求作出反应。

    创建管理线程的流程如下所示:
    (全局变量pthread_manager_request初值为-1

    3 创建管理线程的流程

    初始化结束后,在__pthread_manager_thread中记录了轻量级进程号以及核外分配和管理的线程id2*PTHREAD_THREADS_MAX+1这个数值不会与任何常规用户线程id冲突。管理线程作为pthread_create()的调用者线程的子线程运行,而pthread_create()所创建的那个用户线程则是由管理线程来调用clone()创建,因此实际上是管理线程的子线程。(此处子线程的概念应该当作子进程来理解。)

    __pthread_manager()
    就是管理线程的主循环所在,在进行一系列初始化工作后,进入while(1)循环。在循环中,线程以2秒为timeout查询(__poll())管理管道的读端。在处理请求前,检查其父线程(也就是创建manager的主线程)是否已退出,如果已退出就退出整个进程。如果有退出的子线程需要清理,则调用pthread_reap_children()清理。

    然后才是读取管道中的请求,根据请求类型执行相应操作(switch-case)。具体的请求处理,源码中比较清楚,这里就不赘述了。

    3.
    线程

    LinuxThreads中,管理线程的和用户线程的是分离的,管理线程在进程堆中通过malloc()分配一个THREAD_MANAGER_STACK_SIZE字节的区域作为自己的运行栈。

    用户线程的分配办法随着体系结构的不同而不同,主要根据两个宏定义来区分,一个是NEED_SEPARATE_REGISTER_STACK,这个属性仅在IA64平台上使用;另一个是FLOATING_STACK宏,在i386等少数平台上使用,此时用户线程由系统决定具体位置并提供保护。与此同时,用户还可以通过线程属性结构来指定使用用户自定义的。因篇幅所限,这里只能分析i386平台所使用的两种组织方式:FLOATING_STACK方式和用户自定义方式。

    FLOATING_STACK方式下,LinuxThreads利用mmap()从内核空间中分配8MB空间(i386系统缺省的最大空间大小,如果有运行限制(rlimit),则按照运行限制设置),使用mprotect()设置其中第一页为非访问区。该8M空间的功能分配如下图:

    4 结构示意

    低地址被保护的页面用来监测溢出。

    对于用户指定的,在按照指针对界后,设置线程顶,并计算出底,不做保护,正确性由用户自己保证。

    不论哪种组织方式,线程描述结构总是位于顶紧邻堆栈的位置。

    4.
    线程id和进程id

    每个LinuxThreads线程都同时具有线程id和进程id,其中进程id就是内核所维护的进程号,而线程id则由LinuxThreads分配和维护。

    __pthread_initial_thread
    的线程idPTHREAD_THREADS_MAX__pthread_manager_thread的是2*PTHREAD_THREADS_MAX+1,第一个用户线程的线程idPTHREAD_THREADS_MAX+2,此后第n用户线程的线程id遵循以下公式:


    tid=n*PTHREAD_THREADS_MAX+n+1


    这种分配方式保证了进程中所有的线程(包括已经退出)都不会有相同的线程id,而线程id的类型pthread_t定义为无符号长整型(unsigned long int),也保证了有理由的运行时间内线程id不会重复。

    从线程id查找线程数据结构是在pthread_handle()函数中完成的,实际上只是将线程号按PTHREAD_THREADS_MAX取模,得到的就是该线程在__pthread_handles中的索引。

    5.
    线程的创建

    pthread_create()向管理线程发送REQ_CREATE请求之后,管理线程即调用pthread_handle_create()创建新线程。分配、设置thread属性后,以pthread_start_thread()为函数入口调用__clone()创建并启动新线程。pthread_start_thread()读取自身的进程id号存入线程描述结构中,并根据其中记录的调度方法配置调度。一切准备就绪后,再调用真正的线程执行函数,并在此函数返回后调用pthread_exit()清理现场。

    6.LinuxThreads
    的不足

    由于Linux内核的限制以及实现难度等等原因,LinuxThreads并不是完全POSIX兼容的,在它的发行README中有说明。

    1)
    进程id问题

    这个不足是关键的不足,引起的原因牵涉到LinuxThreads"一对一"模型。

    Linux
    内核并不支持真正意义上的线程,LinuxThreads是用与普通进程具有同样内核调度视图的轻量级进程来实现线程支持的。这些轻量级进程拥有独立的进程id,在进程调度、信号处理、IO等方面享有与普通进程一样的能力。在源码阅读者看来,就是Linux内核的clone()没有实现对CLONE_PID参数的支持。

    在内核do_fork()中对CLONE_PID的处理是这样的:


    if (clone_flags & CLONE_PID) {
    if (current->pid)
    goto fork_out;
    }


    这段代码表明,目前的Linux内核仅pid0的时候认可CLONE_PID参数,实际上,仅在SMP初始化,手工创建进程的时候才会使用CLONE_PID参数。

    按照POSIX定义,同一进程的所有线程应该共享一个进程id父进程id,这在目前的"一对一"模型下是无法实现的。

    2)
    信号处理问题

    由于异步信号是内核以进程为单位分发的,而LinuxThreads的每个线程对内核来说都是一个进程,且没有实现"线程组",因此,某些语义不符合POSIX标准,比如没有实现向进程中所有线程发送信号,README对此作了说明。

    如果核心不提供实时信号,LinuxThreads将使用SIGUSR1SIGUSR2作为内部使用的restartcancel信号,这样应用程序就不能使用这两个原本为用户保留的信号了。在Linux kernel 2.1.60以后的版本都支持扩展的实时信号(从_SIGRTMIN_SIGRTMAX),因此不存在这个问题。

    某些信号的缺省动作难以在现行体系上实现,比如SIGSTOPSIGCONTLinuxThreads只能将一个线程挂起,而无法挂起整个进程。

    3)
    线程总数问题

    LinuxThreads
    将每个进程的线程最大数目定义为1024,但实际上这个数值还受到整个系统的总进程数限制,这又是由于线程其实是核心进程。

    kernel 2.4.x中,采用一套全新的总进程数计算方法,使得总进程数基本上仅受限于物理内存的大小,计算公式在kernel/fork.cfork_init()函数中:


    max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8


    i386上,THREAD_SIZE=2*PAGE_SIZEPAGE_SIZE=2^124KB),mempages=物理内存大小/PAGE_SIZE,对于256M的内存的机器,mempages=256*2^20/2^12=256*2^8,此时最大线程数4096

    但为了保证每个用户(除了root)的进程总数不至于占用一半以上物理内存,fork_init()中继续指定:


    init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
    init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;


    这些进程数目的检查都在do_fork()中进行,因此,对于LinuxThreads来说,线程总数同时受这三个因素的限制。

    4)
    管理线程问题

    管理线程容易成为瓶颈,这是这种结构的通病;同时,管理线程又负责用户线程的清理工作,因此,尽管管理线程已经屏蔽了大部分的信号,但一旦管理线程死亡,用户线程就不得不手工清理了,而且用户线程并不知道管理线程的状态,之后的线程创建等请求将无人处理。

    5)
    同步问题

    LinuxThreads
    中的线程同步很大程度上是建立在信号基础上的,这种通过内核复杂的信号处理机制的同步方式,效率一直是个问题。

    6
    )其他POSIX兼容性问题

    Linux
    中很多系统调用,按照语义都是与进程相关的,比如nicesetuidsetrlimit等,在目前的LinuxThreads中,这些调用都仅仅影响调用者线程。

    7
    )实时性问题

    线程的引入有一定的实时性考虑,但LinuxThreads暂时不支持,比如调度选项,目前还没有实现。不仅LinuxThreads如此,标准的Linux在实时性上考虑都很少。

    展开全文
  • ===========================...获取进程pid ======================================= #include "tlhelp32.h" //获取PID UINT GetProPid(LPCTSTR pszExeFile) { //查找当前的进程的pid UINT nProcessID = 0; PRO
  • 多核 多线程 进程的概念

    千次阅读 2015-05-09 20:13:07
    我们在买电脑的时候经常遇到一些概念,我这电脑是多核多线程的,什么双核的,什么四核、八核的,这种运动速度电脑快!那么这样的电脑为什么运行速度快?当然,运行速度快有很多原因,比如主频、缓存什么的。这里我们...
  • 线程进程是怎样使用多核的

    千次阅读 2018-07-19 16:21:17
    最近由于有抢票的需求,对于一个用户而言,用一个死循环,一个刷票...我在思考如何设置这个线程模型时引出了一个问题,之前还一直都没思考过这个。  多核时,一个线程是始终由一个cpu核运行还是每个cpu核都会运行...
  • 相信用C/C++写过服务的同学对通过响应Ctrl-C(信号量SIG_TERM)实现多线程C进程的优雅退出都不会陌生,典型的实现伪码如下:#include <signal.h>int main(int argc, char * argv[]) { // 1. do some init work ....
  • QNX Neutrino RTOS的实现 从历史上看,QNX的软件系统的"应用压力"是由内存有限的嵌入式系统从内存有限的嵌入式系统中得到的,一直到高端的SMP(对称多处理器)...POSIX实时和线程扩展 由于QNX Neutri...
  • 进程线程的区别(超详细)

    万次阅读 多人点赞 2019-10-03 21:57:46
    进程线程 进程 一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程线程 进程中的一个执行任务(控制单元),负责...
  • 进程线程

    万次阅读 多人点赞 2021-03-17 22:50:20
    进程线程 1 进程 1.1 进程的概念 进程就是正在运行的程序,它代表了程序所占用的内存区域 1.2 进程的特点 独立性 进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有...
  • 线程进程的关系

    万次阅读 2018-12-17 19:41:33
    线程进程1 线程进程2
  • 线程VS进程

    万次阅读 2021-03-10 16:44:19
    什么是线程、什么是进程 在Java中要同时执行(如果是单核,准确的说是交替执行)多个任务,使用的是多线程,而要理解线程,我们先要了解什么是进程什么是线程。 一般的定义:进程是指在操作系统中正在运行的一个应用...
  • 线程(一):创建线程线程的常用方法

    万次阅读 多人点赞 2018-09-01 19:14:23
    一:为什么要学多线程 应付面试 :多线程几乎是面试中必问的题,所以掌握一定的基础知识是必须的...二:进程线程 进程 进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统...
  • 进程与线程进程(英语:Process,中国大陆译作进程,台湾译作行程)是计算机中已运行程序的实体。进程本身不会运行,是线程的容器。程序本身只是指令的集合,进程才是程序(那些指令)的真正运行。若干进程有可能与同一...
  • 线程进程、多线程、多进程 和 多任务 小结

    千次阅读 多人点赞 2019-04-20 11:59:56
    5 线程进程的关系 6 线程进程的区别 7 进程的优缺点 7.1 进程的优点 7.2 进程的缺点 8 线程的优缺点 8.1 线程的优点 8.2 线程的缺点 9 多线程的优缺点 9.1 多线程的优点 9.2 多线程的缺点 10多进程的...
  • 线程进程 概念 进程(process):是指具有已一定功能的独立程序,是系统资源分配的基本单位,在内存中有其完备的数据空间和代码空间,拥有完整的虚拟空间地址。一个进程所拥有的数据和变量只属于它自己。 线程...
  • 线程进程

    千次阅读 2019-11-06 19:36:09
    线程进程 一、线程进程 线程是CPU调度和分派的基本单位。 进程对于操作系统来说就是一个任务。 听起来挺难懂的一句话,我们举一个实际例子:比如现在有一条需要被修的路,这个时候只有一个施工队要修它,...
  • 进程线程的区别

    千次阅读 2019-04-12 16:30:58
    进程线程 进程线程的区别 进程是一个程序在其自身的地址空间中的一次执行活动,是资源申请、调度和独立运行的单位。线程进程的一个单一的连续控制流程,一个进程可以拥有多个线程线程调度的两种方式:抢占式...
  • 线程进程及其调度简介

    千次阅读 2018-05-08 14:46:15
    知识需要不断总结、验证、迭代,知其然,知其所以然。 1、进程和线程进程和...图1 单线程进程图2 多线程进程 进程主要设计目的是隔离,和其他进程地址空间隔离开来;线程是进程的一部分,主要设计目的是通信和并...
  • 线程进程

    千次阅读 2017-09-02 18:51:36
    线程进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的...
  • 进程线程及多线程的概念

    千次阅读 2019-12-28 16:51:51
    什么是进程线程及多线程 进程:一个应用程序开始运行,那么就会存在一个属于这个应用程序的进程进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程进程是处于运行过程中的程序,并且...
  • 线程 vs 进程

    万次阅读 多人点赞 2017-01-22 19:51:54
    进程线程的区别是很重要的一个知识点,也是面试中经常问到的。网上转载博客痕迹明显,且千篇一律。我简单提取下,记录下来,希望能帮到你。另外在 LeetCode 上也有关于此问题的讨论,可以直接浏览“Read more” ...
  • 进程线程合集以及实例

    千次阅读 2020-10-12 11:34:51
    文章目录进程和线程0.1 粗略介绍:0.2 线程进程区别:一.进程1.1 fork创建单进程1.2 multiprocessing:Process 创建子进程1.2 multiprocessing:Pool 创建进程池1.3 进程间通信 公共队列二. 线程2.1 多线程的优点:二. ...
  • Linux进程线程

    千次阅读 2020-02-27 17:59:13
    进程线程 进程 进程基本概念 进程:操作系统对程序的加载并运行的动态概念 进程在内核中的组织形式:进程控制块PCB 进程控制块的组织结构 物理组织结构:进程pcb调度队列 逻辑组织结构:进程创建过程中形成...
  • 线程进程,协程详细解释

    千次阅读 2019-07-23 00:01:15
    什么是进程线程 进程是什么呢? 直白地讲,进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程进程拥有代码和打开的文件资源、数据资源、独立的内存空间。 线程又是什么...
  • iOS 中线程进程的区别

    千次阅读 2015-10-10 21:35:53
    线程进程的区别和联系  (1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。  (2)资源分配给进程,同一进程的所有线程共享该进程的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 855,851
精华内容 342,340
关键字:

线程进程