《VC++深入详解–学习笔记》(15)多线程
Filed Under (VC++ 学习笔记) by panmaoru on 20-12-2009
本章主要介绍多线程程序的编写,并利用多线程技术创建一个网络聊天室。
15.1基本概念
程序是计算机指令的集合,它以文件形式存储在磁盘上。
进程被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动。
进程的组成:操作系统用来管理进程的内核对象和地址空间。进程不执行任何东西,它只是程序的实例,线程的容器或执行环境。创建一个进程之后,操作系统会自动为这个进程创建一个主线程(执行main或者winmain函数的线程)。
线程是进程中的一个实体,是被系统独立调度和分派的基本单位。
线程的组成:线程的内核对象(操作系统用来存放线程统计信息)和线程栈(维护线程在执行代码时候所需要的所有的函数和局部变量)。一个线程之后一个内核对象和一个栈。
15.2线程创建函数
可使用系统提供的API函数CreateThread来创建一个线程。
该函数的原形如下:
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 );
根据CreateThread函数的参数说明,可以基本了解创建一个线程的规则。
15.3简单的多线程示例
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Function1(LPVOID lpParamete);//申明过程函数
void main()
{
HANDLE hThreadl;
hThreadl=CreateThread(NULL,0,Function1,NULL,0,NULL);
CloseHandle(hThreadl);
cout<<"main thread is running"<<endl;
Sleep(10);//主线程执行完毕后,休眠10毫秒,启动子线程
}
DWORD WINAPI Function1(LPVOID lpParamete)
{
cout<<"thread1 is running"<<endl;
return 0;
}
在创建一个线程的时候需要指定过程函数,因此需要在main函数之前申明Function1,也可以将Function1函数的实现放到main函数之前,这样就不需要声明了。
15.4线程同步
操作系统为每一个运行线程安排一定的CPU时间—时间片。在一个多线程的程序中,系统通过一种循环的方式为线程提供时间片,线程在自己的时间片內运行。这就可以会出现一种情况:当多个线性同时对一个全局的对象进行访问时,一个线程已经进入了循环体,这时候时间片结束,该线程进入睡眠状态,系统转向执行另外一个线程。而当另外一个线程执行的时候对全局变量做了修改。当返回到第一个线程的时候,接着从上次时间片结束的地方执行,这时候会出现一些异常。
DWORD WINAPI Function1(LPVOID lpParamete)
{
while(true) {
if(count>0) {
//当线程执行到此的时候,时间片到了,线程1Sleep,开始执行线程2,当线性2完毕之后再回到线程1,接着从此处执行。这时候有可能线程count的值已经为非正常值,如:0。
cout<<"thread1 sell the ticket:"<<count--<<endl;
}
else
break;
}
return 0;
}
DWORD WINAPI Function2(LPVOID lpParamete)
{
while(true) {
if(count>0)
{cout<<"thread2 sell the ticket:"<<count--<<endl; }
else
break;
}
return 0;
}
15.4.1互斥对象实现线程同步
互斥对象mutex属于内核对象,它能够确保线程对当资源的互斥访问权。创建互斥对象的CreateMutex函数的声明如下:
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // 互斥对象安全性,默认NULL BOOL bInitialOwner, // 指定互斥对象的拥有者,默认FALSE LPCTSTR lpName // 指定互斥对象的名称,默认NULL );
