3、多线程(1)

一、概念

1、进程:通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动。一个程序可以有多个进程实例。

2、进程由两个部分组成:

1)操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方。

2)地址空间。它包含所有可执行模块或DLL模块的代码和数据。它还包含动态内存分配的空间。如线程堆栈和堆分配空间。

    进程从来不执行任何东西,它只是线程的容器。若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。

    单个进程可能包含若干个线程,这些线程都“同时”执行进程地址空间中的代码。

每个进程至少拥有一个线程,来执行进程的地址空间中的代码。当创建一个进程时,操作系统会自动创建这个进程的第一个线程,称为主线程。此后,该线程可以创建其他的线程。

一个进程不能读取、写入、或者以任何方式访问驻留在该分区中的另一个进程的数据。

3、线程由两个部分组成:

1)线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。

2)线程堆栈,它用于维护线程在执行代码时需要的所有参数和局部变量。

    线程总是在某个进程环境中创建。系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相同。因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易地互相通信。

线程只有一个内核对象和一个堆栈,保留的记录很少,因此所需要的内存也很少。因为线程需要的开销比进程少,因此在编程中经常采用多线程来解决编程问题,而尽量避免创建新的进程。

操作系统为每一个运行线程安排一定的CPU时间 —— 时间片。

二、线程编程

CreateThread来创建线程。

Main函数是主线程的入口函数。新创建的线程也需要一个入口函数,就在下面的lpStartAddress中定义。

HANDLE CreateThread(

  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

  DWORD dwStackSize,                        // initial stack size

  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function

  LPVOID lpParameter,                       // thread argument

  DWORD dwCreationFlags,                    // creation option

  LPDWORD lpThreadId                        // thread identifier

);

lpThreadId  用来接收线程的ID

DWORD WINAPI ThreadProc( LPVOID lpParameter );

类型和参数要匹配,函数名任意。

关闭线程句柄

BOOL CloseHandle( HANDLE hObject );

注意:关闭句柄并没有终止新创建的线程。只是表示对新创建的线程的引用不敢兴趣,系统会递减新

线程的线程内核对象的使用计数。当使用计数为0的时候,系统就会释放线程内核对象。如果在主线程中没有关闭线程的句柄,始终都会保留一个引用。这样线程内核对象的引用计数就不会为0。即使新线程执行完毕,线程内核对象也不会被释放,只有等到进程终止的时候系统才会为残留的对象做清理工作。所以应该在不再使用线程的句柄的时候将其关闭掉,让线程的线程内核对象的引用计数减1

每个线程有一个引用记数器,当创建成功时初值为2,当你调用一次CloseHandle()时,计数器减一,如果为0,清除线程。线程执行完成计数器还是要减一,如果为0,清除线程。

暂停线程的执行

当线程暂停执行的时候,也就是表示它放弃了执行的权力。操作系统会从等待运行的线程队列中选择一个线程来运行。新创建的线程就可以得到运行的机会。

可以使用函数Sleep:

void Sleep( DWORD dwMilliseconds //sleep time 以毫秒为单位 );

暂停当前线程指定时间间隔的执行。

参考

[1] 孙鑫 《深入VC++》

上一篇:CGI简介 --用C来写CGI程序简要指南


下一篇:4、多线程(2)