2、关键代码段式工做在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,由于在进入关键代码时没法设定超时值。编程
MFC下InitializeCriticalSection()和DeleteCriticalSection()能够放在类的构造函数和析构函数中数据结构
在编写程序时首选关键代码段,但须要很是注意死锁问题!多线程
多线程编程推荐书籍《Windows核心编程》机械工业出版社函数
3、线程、进程、程序的区别spa
程序操作系统 |
计算机指令的集合,它以文件的形式存储在磁盘上线程 |
进程对象 |
一般被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动进程 |
区别:进程是资源申请、调度和独立运行的单位,所以,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能做为独立的运行的单位, 所以,他不占用系统的运行资源。事件
一、操做系统用来管理进程的内核对象。内核对象是操做系统内部分配的一个内存块,内核对象也是系统用来存放关于进程的统计信息的地方。
二、地址空间。它包含全部可执行模块或DLL模块的代码和数据。他还包含动态内存分配的空间。如线程堆栈和堆分配空间。
内核对象:是操做系统内部分配的一个内存块,它是一种只能被内核访问的数据结构, 其成员负责维护该对象的各类信息,应用程序没法找到并直接改变它们的内容,只能经过Windows提供的函数对内核对象进行操做。
进程是不活泼的。进程历来不执行任何东西,它只是线程的容器。
若要使进程完成某项操做,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。
单个进程可能包含若干个线程,这些线程都“同时”执行进程地址空间中的代码。
每一个进程至少拥有一个线程,来执行进程的地址空间中的代码。
当建立一个进程时,操做系统会自动建立这个进程的一个线程,称为主线程。此后,该线程能够建立其余的线程
线程有两个部分组成:
1。线程的内核对象,操做系统用它来对线程实施管理,内核对象也是系统用来存放线程统计信息的地方。
2。线程堆栈,它用于维护线程在执行代码时须要的全部参数和局部变量。
当建立线程时,系统建立一个线程内核对象。
该线程内核对象不是线程自己,而是操做系统用来管理线程的较小的数据结构。
能够将线程内核对象视为由关于线程的统计信息组成的一个小型数据结构。
线程老是在某个进程环境中建立。
系统从进程的地址空间中分配内存,供线程的堆栈使用。
新线程运行的进程环境与建立线程的环境相同。
所以,新线程能够访问进程的内核对象的全部句柄、进程中的全部内存和在这个相同的进程中的全部其余线程的堆栈。这使得单个进程中的多个线程确实可以很是容易的互相通讯。
线程只有一个内核对象和一个堆栈,保留的记录不多,所以所须要的内存也不多。
由于线程须要的开销比进程少,所以在编程中常常采用多线程来解决编程问题,而尽可能避免建立新的进程。
对于单个CPU
操做系统为每个运行线程安排必定的CPU时间——时间片。
系统经过一种循环的方式为线程提供时间片,线程在本身的时间内运行,因时间片至关短,所以,给用户的感受,就好像线程是同时进行的同样。
若是计算机拥有多个CPU,线程就能真正意义上运行了
咱们能够用多进程代替多线程,可是这样不是明智的,由于
1.每新建一个进程,系统要为之分配4GB的虚拟内存,浪费资源;而多线程共享同一个地址空间,占用资源较少
2.在进程之间发生切换时,要交换整个地址空间;而线程之间的切换只是执行环境的改变,效率较高。
4、多线程具体实现
1、互斥对象
这种办法不适合在多核CPU的电脑上 。自动重置(只有一个线程能够获得事件对象)
#include
#include
DWORD WINAPI Fun1Proc (LPVOID lpParameter);
DWORD WINAPI Fun2Proc (LPVOID lpParameter);
int index=0;
int tickets=100;
HANDLE hMutex;
void main()
{
HANDLE hThread1,hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1); //关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1
CloseHandle(hThread2);
//建立互斥对象
hMutex=CreateMutex(NULL,FALSE,NULL); //FALSE标示该线程(main)不得到互斥对象的全部权
Sleep(4000);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter) //当引用计数为0时,终止线程
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE); //INFINITE表示一直等待hMutex有效,不超时退出
if (tickets>0)
{
Sleep(2);
cout<<"thread1 sell tickes :"<<tickets--<<endl;
}
else
{
break;
}
ReleaseMutex(hMutex);
}
return 0;
}
DWORD WINAPI Fun2Proc (LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if (tickets>0)
{
cout<<"thread2 sell tickes :"<<tickets--<<endl;
}
else
{
break;
}
ReleaseMutex(hMutex);
}
return 0;
}
2、事件对象
这种办法不适合在多核CPU的电脑上 。自动重置(只有一个线程能够获得事件对象)
#include
#include
DWORD WINAPI Fun1Proc (LPVOID lpParameter);
DWORD WINAPI Fun2Proc (LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1,hThread2;
HANDLE g_hEvent1;
g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); //让应用程序只能有一个实例
if(g_hEvent1)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run !"<<endl;
return;
}
}
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //建立自动重置事件内核对象,非信号状态
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1); //关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1
CloseHandle(hThread2);
SetEvent(g_hEvent);
Sleep(4000);
CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter) //当引用计数为0时,终止线程
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if (tickets>0)
{
Sleep(2);
cout<<"thread1 sell tickes :"<<tickets--<<endl;
}
else
{
break;
}
SetEvent(g_hEvent);
}
return 0;
}
DWORD WINAPI Fun2Proc (LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if (tickets>0)
{
cout<<"thread2 sell tickes :"<<tickets--<<endl;
}
else
{
break;
}
SetEvent(g_hEvent);
}
return 0;
}
3、关键代码段
又称为临界区:对资源的独占权。
初始化临界区对象函数:InitializeCriticalSection(EnterCriticalSection(LPCRITICAL_SECTION))参数为临界区对象;
申请临界区函数:EnterCriticalSection(LPCRITICAL_SECTION)参数为临界区对象;
释放临界区函数:LeaveCriticalSection(LPCRITICAL_SECTION)参数为临界区对象;
释放临界区资源:DeleteCriticalSection(&g_cs);
使用关键代码段的线程同步代码:
#include
#include
#include
DWORD WINAPI Fun1Proc (LPVOID lpParameter);
DWORD WINAPI Fun2Proc (LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_cs;
void main()
{
HANDLE hThread1,hThread2;
HANDLE g_hEvent1;
g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); //让应用程序只能有一个实例
if(g_hEvent1)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run !"<<endl;
return;
}
}
InitializeCriticalSection(&g_cs); //必须在建立线程以前初始化临界区对象,不然会出错
// g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //建立自动重置事件内核对象,非信号状态
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1); //关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1
CloseHandle(hThread2);
// SetEvent(g_hEvent);
// getchar();
Sleep(4000);
DeleteCriticalSection(&g_cs);
getchar();
// CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter) //当引用计数为0时,终止线程
{
while (TRUE)
{
EnterCriticalSection(&g_cs);
if (tickets>0)
{
Sleep(2);
cout<<"thread1 sell tickes :"<<tickets--<<endl;
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc (LPVOID lpParameter)
{
while (TRUE)
{
EnterCriticalSection(&g_cs);
if (tickets>0)
{
cout<<"thread2 sell tickes :"<<tickets--<<endl;
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
3、线程死锁问题:
#include
#include
#include
DWORD WINAPI Fun1Proc (LPVOID lpParameter);
DWORD WINAPI Fun2Proc (LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
void main()
{
HANDLE hThread1,hThread2;
HANDLE g_hEvent1;
g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); //让应用程序只能有一个实例
if(g_hEvent1)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run !"<<endl;
return;
}
}
InitializeCriticalSection(&g_csA);
InitializeCriticalSection(&g_csB);
// g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //建立自动重置事件内核对象,非信号状态
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1); //关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1
CloseHandle(hThread2);
// SetEvent(g_hEvent);
// getchar();
Sleep(4000);
DeleteCriticalSection(&g_csA);
DeleteCriticalSection(&g_csB);
// CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter) //当引用计数为0时,终止线程
{
while (TRUE) { EnterCriticalSection(&g_csA); // Sleep(1); EnterCriticalSection(&g_csB); if (tickets>0) { Sleep(2); cout<<"thread1 sell tickes :"<<tickets--<<endl; LeaveCriticalSection(&g_csB); LeaveCriticalSection(&g_csA); } else { LeaveCriticalSection(&g_csB); LeaveCriticalSection(&g_csA); break; } } return 0; } DWORD WINAPI Fun2Proc (LPVOID lpParameter) { while (TRUE) { EnterCriticalSection(&g_csB); // Sleep(1); EnterCriticalSection(&g_csA); if (tickets>0) { cout<<"thread2 sell tickes :"<<tickets--<<endl; LeaveCriticalSection(&g_csA); LeaveCriticalSection(&g_csB); } else { LeaveCriticalSection(&g_csA); LeaveCriticalSection(&g_csB); break; } } return 0; }