2017-03-24 12:09:00 yangmx_5 阅读数 890

操作系统中进程和线程的概念理解

进程,是指可以在操作系统中独立运行并且作为资源分配的基本单位。多个进程之间可以并发执行(注意这里的并发执行和并行执行并不是一个概念)。

不同进程之间的切换会浪费较高的系统资源,为了提高系统资源利用率和吞吐量。人们又引入了线程的概念。

线程,是操作系统中作为调度和分派的基本单位,可以理解为轻量级进程。一个进程下可以拥有一个或多个线程,线程在系统中也不能独立于进程之外而存在。

所谓线程,比进程拥有更少的资源,并且同一进程下的不同线程之间可以共享该进程所拥有的资源。所以当进行线程切换时系统的开销明显小于进程切换。

线程的并发性比进程要高,这是由线程的基本属性决定的。线程能够更好的支持多处理机系统。

对于线程的理解可以联系程序中的函数,程序中入口函数main()便是主线程,至于多线程编程就是新建线程函数使得新的函数能和main()函数同时执行(注意这里的同时执行仅仅是我们将任务交付给系统,至于系统底层是并发执行还是并行执行并不是我们能决定的)。


注:
1、 并行执行和并发执行的区别:

a) 并行执行为多个处理机同时对不同的线程任务进行运算处理(现在好多电脑都是多核处理器,所以能进行真正意义上的并行运算)
b) 并发执行为单个处理机以时间片轮转的方式对多个线程进行处理,宏观上用户体验为同时发生的状态。(因为时间片很短通常以毫秒为单位)
c) 现在Hadoop框架便是建立在集群的基础上,通过对多个服务器的协调实现并行运算。

2、 系统底层执行方式与编程无关

a) 值得说明的是我们编程时还要考虑同步问题,这是因为系统底层的操作相对于我们是封装的,我们将多个线程交付给系统后,得到的只是顺序混乱的结果。就像我们将条理分明的猪肉放入碎肉机得到的是肥瘦混合的五花肉一样。
b) 对于这样的五花肉并不是我们想要的结果,这样没有保证程序在每次执行后的结果一致性。这样的程序是不可靠的。所以我们在编程时还要考虑多线程的同步问题。
c) 另一点要区别的是操作系统中的线程同步和编程中的线程同步。编程中的线程同步原因上面已经说明,而操作系统中的线程同步则是因为CPU将内存中的数据拷贝至寄存器时进行不同的运算后重新放入内存时产生冲突。这里可以类比下数据库中的并发控制中的“脏”数据问题。

2019-07-11 12:07:38 gjh13 阅读数 35

在网上看到一个特别形象的举例,让我们理解操作系统中的进程与线程,以及线程同步方式中的"互斥锁"(Mutual exclusion,缩写 Mutex)、"信号量"(Semaphore)

 

网址链接:

http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

 

 

 

2018-11-18 22:59:03 wujianyongw4 阅读数 56

操作系统真象还原是一本介绍如何从零实现一个操作系统的比较不错的书。作者用通俗易懂的语言把操作系统的实现原理非常清晰的讲解出来,非常适合初学者。但是即便已经写的非常好了,读者依然需要认真思考才能将很多问题想清楚。线程调度就是其中一个。

书的第九章是介绍线程的实现以及如何调度的。比较难以理解的是线程调度关于switch_to的理解,源码如下:

/* 实现任务调度 */
void schedule() {

   ASSERT(intr_get_status() == INTR_OFF);

   struct task_struct* cur = running_thread();
   if (cur->status == TASK_RUNNING) { // 若此线程只是cpu时间片到了,将其加入到就绪队列尾
      ASSERT(!elem_find(&thread_ready_list, &cur->general_tag));
      list_append(&thread_ready_list, &cur->general_tag);
      cur->ticks = cur->priority;     // 重新将当前线程的ticks再重置为其priority;
      cur->status = TASK_READY;
   } else {
      /* 若此线程需要某事件发生后才能继续上cpu运行,
      不需要将其加入队列,因为当前线程不在就绪队列中。*/
   }

   ASSERT(!list_empty(&thread_ready_list));
   thread_tag = NULL;     // thread_tag清空
/* 将thread_ready_list队列中的第一个就绪线程弹出,准备将其调度上cpu. */
   thread_tag = list_pop(&thread_ready_list);
   struct task_struct* next = elem2entry(struct task_struct, general_tag, thread_tag);
   next->status = TASK_RUNNING;
   switch_to(cur, next);
}

这是关于调度的程序,我们只关心最后一步将当前进程切换到next进程中去的部分。调度的精髓就在这个函数上。

switch_to:
   ;栈中此处是返回地址         
   push esi
   push edi
   push ebx
   push ebp

   mov eax, [esp + 20]           ; 得到栈中的参数cur, cur = [esp+20]
   mov [eax], esp                ; 保存栈顶指针esp. task_struct的self_kstack字段,
                                 ; self_kstack在task_struct中的偏移为0,
                                 ; 所以直接往thread开头处存4字节便可。
;------------------  以上是备份当前线程的环境,下面是恢复下一个线程的环境  ----------------
   mov eax, [esp + 24]           ; 得到栈中的参数next, next = [esp+24]
   mov esp, [eax]                ; pcb的第一个成员是self_kstack成员,用来记录0级栈顶指针,
                                 ; 用来上cpu时恢复0级栈,0级栈中保存了进程或线程所有信息,包括3级栈指针
   pop ebp
   pop ebx
   pop edi
   pop esi
   ret                           ; 返回到上面switch_to下面的那句注释的返回地址,
                                 ; 未由中断进入,第一次执行时会返回到kernel_thread
~  

由于从c语言函数切换到汇编代码,我们必须小心的是栈,刚刚进入函数时栈顶元素是switch_to的返回地址,接着开始将当前的上下文寄存器压入栈中,接着从switch_to的参数中取出当前进程的pcb地址,pcb的第一个元素是线程栈地址,于是将当前的esp放入线程栈的位置,这样从pcb中就可以找到上下文的寄存器了。接下来就把当前的esp给替换成next的的地址,要从next的pcb中找到next的上下文寄存器并恢复。可以pop出来的寄存器是容易的,但是最关键的eip也就是应该放在esi之上的地方,但是事实上这里存放的是switch_to的返回地址(当然这个switch_to不是现在这个,而是之前的某一个),所以ret只能回到switch_to后继续执行。因为整个的调度程序放在时钟中断服务程序中,因此,执行到最后只能是从中断中返回到中断前的状态,而这个状态正是next的上下文而不是刚刚发生的中断的所保存的上下文。原因是在switch_to函数中已经将esp替换成了next上一次被切换出去的时的栈地址,于是顺着这个栈所保存的寄存器全部是属于next,于是这么回溯回去就可以顺利的切换成next进程。这里的巧妙就在于栈切换,难以理解也在这里。有时间画个流程图会理解的更好。

2016-08-03 12:55:13 qq_24754061 阅读数 577

一,预备知识:

1,(计算机)程序:

     计算机程序或者软件程序(通常简称程序)是指一组指示计算机每一步动作的指令,通常用某种程序设计语言编写,运行于某种目标体系结构上。

2,进程:

     进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

3,程序与进程的总结:

程序是指令、数据及其组织形式的描述,进程是程序的一次运行过程的实体

4,线程:

操作系统能够进行运算调度的最小单位。它被包涵在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程

中可以并发多个线程,每条线程并行执行不同的任务在Unix System 中也被称为轻量进程但轻量进程更多指线,而把用户线程称为线程。

5,进程与线程的关系:

进程与线程的理解


二、典型程序代表:

图形化窗口程序(文字处理软件、图形处理软件),服务器线程池解决方案。以文字处理程序为例说明:(涉及消息处理机制,各个操作系统解决方案略有不同,网络上很多资源)

线程的协调合作


三、以Android中的handler为例说明线程间通信问题:

handler的引入方便的解决了线程间通信的问题,当然你也可以自己封装一个类进行信息的传递(有handler也没必要了,毕竟不是程序设计的重点)。当一个apk文件运行后,他就会在内存中开辟一个内存空间,那么程序的所有线程将会共享这一块内存区域,共享其中的全局变量。每个线程也有自己的独立空间,通过上面的图可以看出来。线程可以访问程序的全局变量,但是,却不能直接访问其他的线程的变量(相对独立)。这个时候,设置一个全局的handler(可以在各个线程所在的一个类中设置,若设置成局部变量,一般也就不具备通信能力了),这样,各个线程可以访问他,使用他设置的存储访问变量的方法,然后,线程间的通信就变得简单了。


四、关于多线程资源竞争的理解:

多线程编程中对资源的合理分配是编程中不可忽略的一个部分,否则,各个线程对共享资源的不合理使用会很容易的造成程序运行结果的错误。了解进程与线程的关系可以很好地理解出现资源竞争的原因(对共享资源的使用),并能很好地解决这个问题,还有助于理解编程语言对于竞争资源采取的解决措施(例如Java中采用锁机制等)。

2017-05-27 22:25:42 weiyongle1996 阅读数 438

一、线程的概念

      线程可以理解为小型、轻型的进程,它是包含在进程中的,线程和进程的具体区别如下:

调度:一个进程可以有多个线程。线程作为CPU调度和分派的基本单位,进程则作为资源分配的基本单位。同一进程中的线程切换不会引起进程切换,从而避免昂贵的系统调用,但是从一个进程的线程切换到另一个进程的线程时,依然会引起进程切换。

切换时的系统开销:由于在创建或者撤销进程时,系统都要为之分配或回收资源,因此,操作系统所付出的开销将显著地大于创建或者撤消线程的开销。在进程切换时,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置,而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作。同时,由于同一个进程中的多个线程具有相同的地址空间,致使它们之间的同步和通信的实现也变得比较容易。

占用的资源:进程是拥有系统资源的一个独立的单位,它可以拥有自己的资源。线程自己一般不拥有资源(有一点必不可少的资源,包括程序计数器,一组寄存器和栈等),但它可以访问其隶属进程的资源,如进程代码段,数据段以及系统资源(已打开的文件,I/O设备等)。

单线程进程与多线程进程区别如下:

多线程的优点

  1. 响应度高(Responsiveness):即使其部分阻塞或执行较冗长操作,该程序仍能继续执行,从而增加了对用户的相应程度。

  2. 资源共享(Resource Sharing):线程默认共享它们所属进程的内存和资源。代码和数据共享的优点是它允许一个应用程序在同一地址空间有多个不同的活动线程。

  3. 经济(Economy):进程创建所需要的内存和资源的分配比较昂贵。由于线程能共享它们所属进程的资源,所以创建和切换线程会更为经济。

  4. 可拓展性(Scalability):多线程的优点之一是能充分使用多处理器体系结构。以便每个进程能并行运行在不同的处理器上。不管有多少CPU,单线程进程只能运行在一个CPU上,在多CPU上使用多线程加强了并发功能。

二、多线程模型

     有两种不同的方法来提供线程支持:用户层的用户线程(User Threads)和内核层的内核线程。用户线程受内核支持,而无需内核管理;而内核线程由操作系统支持和管理。事实上所有当代操作系统都支持内核线程。

用户线程与内核线程具有的关系如下:

1.多对一模型:多对一模型将许多用户级线程映射到一个内核线程。线程管理由线程库在用户空间进行的,因而效率比较高。但是如果一个线程执行了阻塞系统调用,那么整个线程会阻塞。因为任意时刻只能有一个线程能够访问内核,多个线程不能并行运行在多处理器上。

2.一对一模型:一对一模型每个用户线程映射到一个内核线程。该模型在一个线程执行阻塞系统调用时,能允许另一个线程继续执行。它也允许多个线程能并行运行在多处理器系统上,这种模型的唯一缺点是每创建一个用户线程就会创建一个相应的内核线程。由于创建内核线程的开销会影响应用程序的性能,所以这种模型的绝大多数实现限制了操作系统所支持的线程数量。

3.多对多模型:多对多模型多路复用了许多用户线程到同样数量或更小数量的内核线程上。多对多模型没有这两者的缺点:开发人员可创建任意多的用户线程,并且相应内核线程能在多处理器系统上并发执行。而且当一个线程执行阻塞系统调用时,内核能调度另一个线程来执行。

参考博客:http://blog.csdn.net/u013007900/article/details/49964515

操作系统-线程

阅读数 127

没有更多推荐了,返回首页