根据一个最详细的多线程的学习笔记,做出自己的理解:http://blog.youkuaiyun.com/morewindows/article/details/7442333
1. 首先是一个最简单的开始:
这个程序的主线程会创建了一个子线程并等待其运行完毕,子线程就输出它的线程ID号然后输出一句经典名言——Hello World。
#include "iostream"
#include "windows.h"
using namespace std;
//子线程函数
DWORD WINAPI ThreadFun(LPVOID pM)
{
printf("子线程的ID号为: %d \n 子线程输出Hello World\n", GetCurrentThreadId());
return 0;
}
//主函数, 所谓主函数其实就是主线程执行的函数。
int main()
{
printf(" so easy for 多线程:)\n");
HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
WaitForSingleObject(handle, INFINITE);
return 0;
}

其中每一次的ID会变化的。
第一个 CreateThread
函数功能:创建线程
*****第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。
*****第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
函数返回值:
成功返回新线程的句柄,失败返回NULL。
第二个 WaitForSingleObject
函数功能:等待函数 – 使线程进入等待状态,直到指定的内核对象被触发。
函数原形:
DWORDWINAPIWaitForSingleObject(
HANDLEhHandle,
DWORDdwMilliseconds
);
函数说明:
第一个参数为要等待的内核对象。
第二个参数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入INFINITE表示无限等待。
因为线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以用WaitForSingleObject()来等待一个线程结束运行。
函数返回值:
在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED
CreateThread 由多个线程访问修改导致的数据覆盖问题。
CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
是相互配合使用的,而对于_beginthreadex为:
unsigned int __stdcall ThreadFun(PVOID pM)
HANDLE handle =(HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
2. 解决一个问题 读写时,我们需要有一种方法能够保证对一个值的递增操作是原子操作——即不可打断性,一个线程在执行原子操作时,其它线程必须等待它完成之后才能开始执行该原子操作。
多个线程存在问题:这样由于线程执行的并发性,很可能线程A执行到第二句时,线程B开始执行,线程B将原来的值又写入寄存器eax中,这样线程A所主要计算的值就被线程B修改了。这样执行下来,结果是不可预知的——可能会出现50,可能小于50。
利用新的函数
1.增减操作
LONG__cdeclInterlockedIncrement(LONG volatile* Addend);
LONG__cdeclInterlockedDecrement(LONG volatile* Addend);
返回变量值运算后与0比较的值,等于0返回0,大于0返回正数,小于0返回负数。
LONG__cdeclInterlockedAdd(LONG volatile* Addend, LONGValue);
返回运算后的值,注意!加个负数就是减。
2.赋值操作
LONG__cdeclInterlockedExchange(LONG volatile* Target, LONGValue);
Value就是新值,函数会返回原先的值。
这样可以打印成功,都是50. 但是当递增变为100时,结果出现了问题:
#include "iostream"
#include "windows.h"
#include "process.h"
using namespace std;
volatile long g_nLoginCount;
//子线程函数
unsigned int __stdcall ThreadFun(PVOID pM)
{
Sleep(100);
//printf("子线程的ID号为: %d \n 子线程输出Hello World\n", GetCurrentThreadId());
InterlockedIncrement((LPLONG)&g_nLoginCount);
Sleep(50);
return 0;
}
//主函数, 所谓主函数其实就是主线程执行的函数。
int main()
{
printf(" so easy for 多线程:)\n");
const DWORD Thead_Num = 100; //change to 100
HANDLE handle[Thead_Num];
int _new = 20;
while(_new--)
{
g_nLoginCount = 0;
for( int i = 0; i < Thead_Num; i++)
handle[i] =(HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
WaitForMultipleObjects(Thead_Num, handle, TRUE, INFINITE); //单个的等待,可以多个
cout << "the note:" << g_nLoginCount << endl;
}
return 0;
}
3.这个问题涉及到线程的同步和互斥,是一道非常有代表性的多线程同步问题,如果能将这个问题搞清楚,那么对多线程同步也就打下了良好的基础。
消除:关键段
函数功能:进入关键区域
函数原型:
void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:系统保证各线程互斥的进入关键区域。
***然后在经典多线程问题中设置二个关键区域。一个是主线程在递增子线程序号时,另一个是各子线程互斥的访问输出全局资源时关键段可以用于线程间的互斥,但不可以用于同步,
利用event可以进行同步:
//经典线程同步互斥问题
#include "iostream"
#include "windows.h"
#include "process.h"
using namespace std;
//设置两个关键区域,第一个是主线程在递增子线程序号时,另一个是各子线程互斥的访问输出全局资源时。
long g_nNum; //全局资源
unsigned int __stdcall Fun(void *pPM); //线程函数
const int Thread_Num = 10; //子线程个数
//关键段变量的申请 //用于各子线程间的互斥
CRITICAL_SECTION g_csTreadCode;
//event //用于同步
HANDLE g_hThreadEvent;
int main()
{
g_nNum = 0;
HANDLE handle[Thread_Num];
g_hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //第二个参数FALSE自动置位
//关键段初始化
//InitializeCriticalSectionAndSpinCount(&g_csTreadParameter, 4000);
InitializeCriticalSectionAndSpinCount(&g_csTreadCode, 4000);
int i = 0;
while(i < Thread_Num)
{
//EnterCriticalSection(&g_csTreadParameter); //进入子线程序号关键区域
handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); //&i Argument list to be passed to a new thread or NULL.
WaitForSingleObject(g_hThreadEvent, INFINITE);
i++;
}
//保证子线程已经全部运行结束
WaitForMultipleObjects(Thread_Num, handle, TRUE, INFINITE);
//DeleteCriticalSection(&g_csTreadParameter);
CloseHandle(g_hThreadEvent);
DeleteCriticalSection(&g_csTreadCode);
return 0;
}
unsigned int __stdcall Fun(void *pPM)
{
//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来
int nTreadNum = *(int *)pPM;
//LeaveCriticalSection(&g_csTreadParameter); //离开子线程序号关键区域
SetEvent(g_hThreadEvent); //触发事件
Sleep(50);
EnterCriticalSection(&g_csTreadCode); //进入格子线程互斥区域
g_nNum++; //处理全局资源
Sleep(0);
cout << "number of thread is:" << nTreadNum << "处理全局资源" << g_nNum << endl;
LeaveCriticalSection(&g_csTreadCode); //离开各子线程互斥区域
return 0;
}
//提高关键段的性能,旋转锁
//初始化关键段,并设置旋转次数。
//BOOL InitializeCriticalSectionAndSpinCount()
利用时间进行实现同步,同步是多个线程同时,而互斥是多个线程不能同时访问同一资源。并且PulseEvent将实现一个事件脉冲:
//PluseEvent()
#include "iostream"
#include "windows.h"
#include "process.h"
#include "conio.h"
using namespace std;
HANDLE g_nThreadEvent;
//快线程
unsigned int __stdcall FastThreadFun(void *pPM)
{
Sleep(10);
cout << "启动:" << (PSTR)pPM;
WaitForSingleObject(g_nThreadEvent, INFINITE);
cout << "wait the event for 触发,结束:" << (PSTR)pPM << endl;
return 0;
}
//慢线程
unsigned int __stdcall SlowThreadFun(void *pPM)
{
Sleep(100);
cout << "启动:" << (PSTR)pPM;
WaitForSingleObject(g_nThreadEvent, INFINITE);
cout << "wait the event for 触发,结束:" << (PSTR)pPM << endl;
return 0;
}
int main()
{
BOOL bManualReset = TRUE; //手动还是自动
g_nThreadEvent = CreateEvent(NULL, bManualReset, FALSE, NULL);
if(bManualReset == TRUE)
{
cout << "手动置位事件";
}
else
cout << "自动置位事件";
char fastThreadName[5][20] = {"fast1:", "fast2:", "fast3:", "fast4:", "fast5:"};
char slowThreadName[2][20] = {"slow1:", "slow2:"};
int i = 0;
for(i = 0; i < 5; i++)
_beginthreadex(NULL, 0, FastThreadFun, fastThreadName[i], 0, NULL);
for(i = 0; i < 2; i++)
_beginthreadex(NULL, 0, SlowThreadFun, slowThreadName[i], 0, NULL);
Sleep(50);
cout << "现在触发一个子线程:" <<endl;
PulseEvent(g_nThreadEvent);
Sleep(3000);
cout << "主线程结束" << endl;
CloseHandle(g_nThreadEvent);
return 0;
}
4.互斥量的实现:
//PluseEvent()
#include "iostream"
#include "windows.h"
#include "process.h"
#include "conio.h"
using namespace std;
HANDLE g_nThreadMutex;
CRITICAL_SECTION g_csThreadCode;
long g_nNum;
const int Thread_Num = 10;
//快线程
unsigned int __stdcall FastThreadFun(void *pPM)
{
Sleep(10);
int nThreadNum = *(int *)pPM;
ReleaseMutex(g_nThreadMutex);
EnterCriticalSection(&g_csThreadCode); //进入格子线程互斥区域
g_nNum++;
//WaitForSingleObject(g_nThreadEvent, INFINITE);
cout << "wait the event for 触发,结束:" << nThreadNum << endl;
cout << g_nNum << endl;
LeaveCriticalSection(&g_csThreadCode); //离开各子线程互斥区域
return 0;
}
int main()
{
HANDLE handle[Thread_Num];
InitializeCriticalSectionAndSpinCount(&g_csThreadCode, 4000);
g_nThreadMutex = CreateMutex(NULL, FALSE, NULL);
int i = 0;
while(i < Thread_Num)
{
//OpenMutex(MUTEX_ALL_ACCESS, TRUE, NULL);
handle[i] = (HANDLE)_beginthreadex(NULL, 0, FastThreadFun, &i, 0, NULL);
WaitForSingleObject(g_nThreadMutex, INFINITE);
i++;
}
WaitForMultipleObjects(Thread_Num, handle, TRUE, INFINITE);
CloseHandle(g_nThreadMutex);
DeleteCriticalSection(&g_csThreadCode);
for(i = 0; i < Thread_Num; i++)
CloseHandle(handle[i]);
return 0;
}