《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
	
);


一个线程需要申请才能获取对一个互斥对象的所有权,等使用结束之后,需要释放对该对象的所有权。申请和释放的函数申明如下:

DWORD WaitForSingleObject(
	
  HANDLE hHandle,        // 互斥对象句柄
	
  DWORD dwMilliseconds   //等待时间,默认INFINITE
	
);
	
BOOL ReleaseMutex(
	
  HANDLE hMutex   //互斥对象句柄
	
);

使用互斥对象的原则是谁拥有谁释放。使用互斥对象实现的火车售票程序的代码如下:

#include <windows.h>
	
#include <iostream.h>
	
DWORD WINAPI Function1(LPVOID lpParamete);
	
DWORD WINAPI Function2(LPVOID lpParamete);
	
int count=100;
	
HANDLE hMutex;
	
void main()
	
{
	
       hMutex=CreateMutex(NULL,TRUE,NULL);//此处第二个参数设置为真相当于把互斥对象授权给主线程,因此需要在主线程中释放
	
       HANDLE hThreadl;
	
       hThreadl=CreateThread(NULL,0,Function1,NULL,0,NULL);
	
       CloseHandle(hThreadl);
	
       HANDLE hThread2;
	
       hThread2=CreateThread(NULL,0,Function2,NULL,0,NULL);
	
       CloseHandle(hThread2);
	
       ReleaseMutex(hMutex);//释放,谁拥有谁释放
	
       Sleep(4000);
	
      
	
}
	
DWORD WINAPI Function1(LPVOID lpParamete)
	
{
	
       while(true)
	
       {
	
              WaitForSingleObject(hMutex,INFINITE);
	
              if(count>0)
	
              {
	
                     //Sleep(1);
	
                     cout<<\"thread1 sell the ticket:\"<<count--<<endl;
	
              }
	
              else
	
                     break;
	
              ReleaseMutex(hMutex);
	
       }
	
       return 0;
	
}
	
DWORD WINAPI Function2(LPVOID lpParamete)
	
{
	
       while(true)
	
       {
	
              WaitForSingleObject(hMutex,INFINITE);
	
              if(count>0)
	
              {
	
                     //Sleep(1);
	
                     cout<<\"thread2 sell the ticket:\"<<count--<<endl;
	
              }
	
              else
	
                     break;
	
              ReleaseMutex(hMutex);
	
       }
	
       return 0;
	
}

15.5网络聊天室的实现

代码就不贴上来了。

Comments (1)

  1. 多线程俺至今还没弄明白到底是咋回事,互斥对象,关键代码段用的稀里糊涂

Post a comment