一、创建线程
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //新线程安全属性
_In_ SIZE_T dwStackSize, //线程初始化时地址空间大小
_In_ LPTHREAD_START_ROUTINE lpStartAddress, //线程函数地址
_In_opt_ LPVOID lpParameter, //传递给线程的命令行参数
_In_ DWORD dwCreationFlags, //线程创建后是否立即运行
_Out_opt_ LPDWORD lpThreadId //线程ID号
);
下面为代码:
// create_thread.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
DWORD WINAPI myfun1(
LPVOID lpParameter
);
DWORD WINAPI myfun2(
LPVOID lpParameter
);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h1, h2;
h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
printf("线程1开始运行!\r\n");
h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
printf("线程2开始运行!\r\n");
::CloseHandle(h1);
::CloseHandle(h2);
if (getchar() == 'q')
{
return 0;
}
else
{
::Sleep(100);
}
return 0;
}
DWORD WINAPI myfun1( LPVOID lpParameter )
{
printf("线程1正在运行!\r\n");
return 0;
}
DWORD WINAPI myfun2( LPVOID lpParameter )
{
printf("线程2正在运行!\r\n");
return 0;
}
运行即可知道,其不同步。
二、多线程同步
同步有多种方法,如临界区对象、事件对象、互斥对象。
临界区对象:
初始化临界区
void WINAPI InitializeCriticalSection(
_Out_ LPCRITICAL_SECTION lpCriticalSection
);
进入临界区函数:
void EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
释放临界区:
void LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
void DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
作用防止内存错误
代码如下:
// create_thread.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
DWORD WINAPI myfun1(
LPVOID lpParameter
);
DWORD WINAPI myfun2(
LPVOID lpParameter
);
static int a1 = 0;
CRITICAL_SECTION Section;
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&Section);
HANDLE h1, h2;
h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
printf("线程1开始运行!\r\n");
h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
printf("线程2开始运行!\r\n");
::CloseHandle(h1);
::CloseHandle(h2);
::Sleep(1000);
printf("正常退出程序请按'q'\r\n");
if (getchar() == 'q')
{
DeleteCriticalSection(&Section);
}
else
{
return 0;
}
return 0;
}
DWORD WINAPI myfun1( LPVOID lpParameter )
{
while (1)
{
EnterCriticalSection(&Section);
a1++;
if (a1 < 1000)
{
::Sleep(1000);
printf("线程1正在计数%d\r\n", a1);
LeaveCriticalSection(&Section);
}
else
{
LeaveCriticalSection(&Section);
break;
}
}
return 0;
}
DWORD WINAPI myfun2( LPVOID lpParameter )
{
while (1)
{
EnterCriticalSection(&Section);
a1++;
if (a1 < 1000)
{
::Sleep(1000);
printf("线程2正在计数%d\r\n", a1);
LeaveCriticalSection(&Section);
}
else
{
LeaveCriticalSection(&Section);
break;
}
}
return 0;
}
其结果如下:
可以知道,在现在多核下,以上建立临界区不能很好的同步。
事件对象:
创建一事件对象
HANDLE WINAPI CreateEvent(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
_In_ BOOL bManualReset, //表示人工重置还是自动重置,true人工,false自动
_In_ BOOL bInitialState, //初始状态,true有状态,false无信号状态
_In_opt_ LPCTSTR lpName
);
DWORD WINAPI WaitForSingleObject(
_In_ HANDLE hHandle, //表示所等待的事件对象句柄
_In_ DWORD dwMilliseconds //等待时间
);
代码如下:
// create_thread.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
DWORD WINAPI myfun1(
LPVOID lpParameter
);
DWORD WINAPI myfun2(
LPVOID lpParameter
);
int a1 = 0;
HANDLE hevent;
DWORD WINAPI WaitForSingleObject(
_In_ HANDLE hHandle, //表示所等待的事件对象句柄
_In_ DWORD dwMilliseconds //等待时间
);
HANDLE WINAPI CreateEvent(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
_In_ BOOL bManualReset, //表示人工重置还是自动重置,true人工,false自动
_In_ BOOL bInitialState, //初始状态,true有状态,false无信号状态
_In_opt_ LPCTSTR lpName
);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h1, h2;
hevent = ::CreateEvent(NULL, FALSE, false, NULL);
::SetEvent(hevent);
h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
printf("线程1开始运行!\r\n");
h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
printf("线程2开始运行!\r\n");
::CloseHandle(h1);
::CloseHandle(h2);
::Sleep(20000);
return 0;
}
DWORD WINAPI myfun1( LPVOID lpParameter )
{
while (1)
{
::WaitForSingleObject(hevent, INFINITE);
::ResetEvent(hevent);
if (a1 < 10000)
{
a1++;
::Sleep(1000);
printf("线程1正在计数%d\r\n", a1);
::SetEvent(hevent);
}
else
{
::SetEvent(hevent);
break;
}
}
return 0;
}
DWORD WINAPI myfun2( LPVOID lpParameter )
{
while (1)
{
::WaitForSingleObject(hevent, INFINITE);
::ResetEvent(hevent);
if (a1 < 10000)
{
a1++;
::Sleep(1000);
printf("线程2正在计数%d\r\n", a1);
::SetEvent(hevent);
}
else
{
::SetEvent(hevent);
break;
}
}
return 0;
}
结果如下:
可以看出用事件对象可以达到同步效果,据其原理是用了WaitForSingleObject,其参数设置成永远等待
互斥对象:
互斥对象不仅可以同步线程,也可以同步进程。
创建互斥对象:
HANDLE WINAPI CreateMutex(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
_In_ BOOL bInitialOwner, //表示该互斥对象的拥有者,true表示创建该互斥对象的线程拥有其所有权,反之,则没
_In_opt_ LPCTSTR lpName //互斥对象的名字
);
代码如下:
// create_thread.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
DWORD WINAPI myfun1(
LPVOID lpParameter
);
DWORD WINAPI myfun2(
LPVOID lpParameter
);
int a1 = 0;
HANDLE hmutex;
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h1, h2;
hmutex = ::CreateMutex(NULL, FALSE, NULL);
h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
printf("线程1开始运行!\r\n");
h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
printf("线程2开始运行!\r\n");
::CloseHandle(h1);
::CloseHandle(h2);
::Sleep(20000);
return 0;
}
DWORD WINAPI myfun1( LPVOID lpParameter )
{
while (1)
{
::WaitForSingleObject(hmutex, INFINITE);
if (a1 < 10000)
{
a1++;
::Sleep(1000);
printf("线程1正在计数%d\r\n", a1);
::ReleaseMutex(hmutex);
}
else
{
::ReleaseMutex(hmutex);
break;
}
}
return 0;
}
DWORD WINAPI myfun2( LPVOID lpParameter )
{
while (1)
{
::WaitForSingleObject(hmutex, INFINITE);
if (a1 < 10000)
{
a1++;
::Sleep(1000);
printf("线程2正在计数%d\r\n", a1);
::ReleaseMutex(hmutex);
}
else
{
::ReleaseMutex(hmutex);
break;
}
}
return 0;
}
同样也能完成线程同步