多线程编程学习笔记1

在计算机中处于运行状态的任何一个程序都是一个进程。抽象一点来讲呢,进程是一些所有权的集合。比如一个进程拥有内存,cpu运行时间等一些列资源,

为其子线程的运行提供运行环境。每个进程有他自己的地址空间即进程地址空间和动态分配的内存,以及文件例如IO,线程和其他一些模块。

一个进程的状态有以下几种

1。运行(正在使用cpu)

2。就绪(当前能够运行-已经取得运行所需的所有资源 但由于系统正在运行其他进程而需等待)

3。阻塞(由于还未能得到所需资源或其他原因(死锁等),导致当前该进程不能运行,需等待外部事件的发生,目的即解除这种堵塞状态)

知识点:在传统的进程中,每个进程中只有一个控制线程,进程只是表达了所有权的概念,线程才是程序的最小执行单位。(很书呆子的书法,具体意义不明白,一直没什么书说清楚到底是个什么东西)

简单说,线程就是程序的一条执行路径,是操作系统分配cpu时间的基本实体。意思就是cpu是按线程来进行分配分时间片的。一个进程以一个主线程开始(抽象的概念),如果需要还可以创建更多的线程。通常所说的执行一个进程准确的讲应该是执行进程中的一个线程。一个进程的多个线程共享进程内的公共资源(因为进程是系统分配资源的基本单位,之前已经说明),同一进程的所有线程共享同样的虚拟地址空间 全局变量。
一个Windows2000进程包括以下几个部分:

1一个集合 集合中的内容为可执行执行

2一个私有(该进程独有)的虚拟地址空间,这个空间就是一系列改进程可以用的虚拟内存地址的结合(操作系统分配的一系列虚拟地址,到时实际运行的时候转成物理地址)

3系统资源,包括信号量(用于标示进程状态)通信端口(一看就是通信用的)文件等

4至少一个线程(传说中的主线程)执行

4进程的ID号(操作系统分配的好管理)

一个线程包括以下几个部分

1表示处理器状态的寄存器(很抽象 没说清楚,大意是用一个寄存器保存处理器就是cpu的状态,时刻侦测,发现可用就好让皇帝(cpu)来自己的寝宫处理)

2两个堆栈(数据结构概念),黑白两道都要搞好装备,一个在线程处于核心模式(应该是ring0-黑道势力)使用,另一个在线程处于用户模式(估计是ring3-白道势力)使用

3一个由子系统(太抽象,没说清楚什么子系统),运行时间库(更是没说清楚OMG)和动态链接库(总算有一个耳熟的概念)使用的私有存储区域

意思是一个私有存储区域(该线程拥有的,一些个私人物品肯定不方便公共使用了),给子系统(估计是线程子系统),运行时库(线程运行的时候用到的东东-应该是静态的)和动态链接库使用的一个区域。

4最后肯定还要给个ID号(不然不好管理,类似我们的身份证,不然ZF怎么管理呢)

现在呢就要讲到一个重要的问题(不要瞌睡)那就是线程的同步问题,这个问题可就是一个很大的问题
你想啊,一个程序就像住在一个大集体的一个家庭,包含一个或多个组员(进程),每个进程呢由一个或多个线程构成。这众口难调,如果不好好管理,怎么做到协调以及同步呢。
线程呢是通过休眠(也就是睡觉,暂停所有执行,这太舒服了)来做到与进程中的其他线程同步(要是现实情况是这样那真是和谐)当然了,你线程也得做点事情才有这样的待遇,那就是你睡觉前得吱一声,就是你得告诉管家(Windows)什么情况下把你叫醒(不然都睡觉了,任务怎么办,什么时候可以完工呢)。管家帮你记着这个事情,到了把你叫醒的情况,他把你叫醒了说该工作了,然后继续工作。这样的情况就是线程和事件一起被同步(很明显的嘛,某事件即唤醒你的事件一发生你就行了工作了)。方法当然不止这一个了,也可以由一些特殊的同步对象(不仅仅是事件)来进行线程同步。
这些著名的东东包括
1.临界段 这个东西可就厉害了,他使用了一招是这样的,他把所有线程(住户)必须用到的资源给锁起来了,有钥匙你才可以运行,这样就可以很好的管理各个线程(住户),下一位要用就必须等到前一位搞完所有事情给钥匙你才可以用。一般用户程序使用这个东东来阻止两个线程同时访问共享的资源,以免读脏数据。
2互斥量,这个东西和临界段你还别说确实很像,区别就在于这个东东不仅仅保护进程内的,他还管的很宽,他还保护系统中进程之间的资源。实现的方式具体点就是为互斥量提供一个名字,互斥量名来进行进程间资源共享协调。
3就是事件了,事件就是个交通协管员,控制线程之间有条不紊的运行,我告诉你某个操作可以开始就开始,我通知你结束靠边停车你就得照办。这就很类似交通的情况了,没红灯之前,线程就一直挂起就类似于汽车一直开啊开啊的,当红灯了,通知你了,你就得照办停车。程序开发中的情况就是一般用事件来进行线程之间的通信。
4就是一个叫信号量的东东了,这个东西和互斥类似,只不过互斥呢在同一时刻只允许一个线程访问数据,而信号量这个东东允许同时多个线程访问它的数据。当然据我估计这样出现混乱的概率肯定比互斥量多了,你想一个一个来自然出错概率低,一批一批自然难管理了。这里有个难点,说的也很抽象,意思是操作系统不知道哪个线程拥有信号量,想想也是,一批一批太多人了嘛,我只要保证资源数正确就行了,你一大群人用水,我不管某个时候谁在用水,反正水表正确计数,用完了,没水了,没资源了,就注销资源对象了。
下面隆重介绍一个超级耍酷的东东,内核对象,听听 内核两个字就不是一般的和我一样的菜鸟程序员玩的东西,更何况还是面向对象的对象呢,是吧。
其实这东西就跟魔术一样,看着很恐怖很神奇很NB的,实际说穿了不值半毛钱,平时的c++编程中,什么类啊对象等不是由我们这些自命的程序员创建的嘛,那内核对象呢顾名思义就是内核创建的,内核是谁呢,那还用说就是操作系统了,所以内核对象一般是指由操作系统创建和管理的对象。
常见的内核对象就多了,例如事件对象,文件映射对象(很抽象),文件对象,邮槽对象,互斥对象等。
不管是不是内核,反正你撑死了就是一个对象了,尽管前面戴着一个很吓人的内核的帽子,既然是对象那就对应一块内存,普通的对象呢是程序员给它的家(当然很多时候我觉得是编译器帮的忙)即给它分配了块内存。内核对象呢就是由操作系统给分配的一块内存,并且只能被操作系统用,所谓的皇家专用,给打了标记了。这个内存块也就是内核对象自然包含了很多信息,所以实际上也就是一数据结构包含了该对象的所有信息。刚都说了,内核对象是由内核分配的,那是官家专用的,只能官家使用。普通的平头小百姓应用程序自然是不能访问他们,即定为这些数据结构,门都不让进,改变里面的东西自然是更不可能了。
当然了哲学思想可以说无所不在,任何事情都不是绝对的,你要访问也不是绝对不可以,但是你必须得走正规渠道,就像你去政府,你可以随便去吗,肯定不可以要按政府规章制度来。所以普通程序只能通过win32提供的一套接口就是所谓的传说中的API函数去操作这些所谓的内核对象及其对应的数据结构了。
当调用相应的接口函数创建内核对象时,函数办完事情返回一个扇子柄,也就是传说中的句柄,然后进程中的所有线程,所有老百姓都可以用了,大家共享这唯一的一把扇子。操作系统肯定要健壮,不然哪有精力控制整个计算机,所有规定刚刚创建的内核对象归创建者该进程所有,老王走正规政府渠道得到的批文自然只属于老王一家老小所有,老李你要用要么干看着要么自己申请去。
但是多年的传统导致了实际上原则也是在某些特殊情况下可以变一下的,要灵活适应需求嘛。
老王奉天从政府官家那得到了内核对象,尚方宝剑,那自然他儿子嘛子承父业自然也拥有了该尚方宝剑-内核对象。
还有一个办法,老王把得到的尚方宝剑取个名,然后标记一下放进村头的保险柜,村长(操作系统)保管锁匙,谁用就去申请,大家都可以用,这有个学名叫什么命名对象。
还有一个就是最最厉害的无敌大法就是复制大法,现如今什么都可以复制,一个内核对象自然也可以复制撒。

这里要着重理解一下对象和句柄,对象在面向对象程序设计中大家都知道,对象是什么,对象就是类的一个实例,那句柄呢,句柄就是系统也就是操作系统创建对象之后总得给你什么东东吧,不然你咋知道创建什么或者创建成了没有呢,通过句柄我们应用程序就可以访问对象了,其实句柄是一长串数字,反正我们不用记着,就类似身份证,反正是政府发的,句柄呢就是操作系统发的,根据句柄就可以访问对象就可以了。其实我心里说这不是忽悠用户嘛,要讲也要来弄去脉讲清楚撒。
现在安全意识大家已经都有了,大家去超市买东西都会注意什么QS标示,什么保质期,什么成分等等。所以内核对象既然是操作系统制造,那自然给点什么标识才好。操作系统是皇家级别自然要有个专门的术语即安全描述符,仅仅对它制造生产的内核对象有用。小百姓可没资格搞什么安全描述符,那不是笑掉牙了嘛。安全描述符郑重其事的描述谁生产,谁可以使用,谁不可以使用等等一系列属性。我们都是聪明人都是程序员,一看这样的需求,在咱们的潜意识里,这样的情况肯定是用结构体撒,所以不要小看结构体,大名鼎鼎的微软用的是超级超级多的。这个结构体有个名字叫SECURITY_ATTRIBUTES,英文好的同学一看就知道是安全属性即安全描述符。关于该结构体的描述大家可以参考官方文档即著名的MSDN文档。
最后再来说说很有难度的线程调度,调度可以说是国家的一个很大的问题啊,南水北调,交通调度啊等等都是很有难度的事情。操作系统课本中就提及了这样的概念,有一些操作系统就采用轮询的办法来调度线程,小王来让你玩会,玩了一半,得了,该小李了,小李玩上了,小王就等着,干着急,这是制度,没办法。windows系列那是西方的玩意,所有采用的抢先式的做法,提高了效率,这样自然给线程调度增加了难度。Windows采用的是优先级的办法,给每个进程每个线程标优先级总共有32级,0最低,31最高。


 

原文地址:https://www.cnblogs.com/feng801/p/1754760.html