场景:
1. 在多线程程序里,临界区是最常见的同步访问共享资源的最简单的解决方案.
2. pthread是跨平台的线程模型,那么它和本地的线程模型的临界区编程有什么区别呢?
临界区:
临界区是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。这是让若干代码能够"以原子操作方式"来使用资源的一种方法。
所谓原子(atomic)操作方式,是指这段代码知道没有别的线程要访问这个资源.
说明:
1. MacOSX,Windows有自己的线程模型, pthread可以说是跨平台的线程编程模型解决方案,当然对pthread不熟悉的也可以使用本地线程模型,
其实pthread的win32版本也是基于本地线程模型的, pthread-win32的mutex是用户态的临界区实现,和win32的内核对象Mutex不同.
2. POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,
都使用Pthreads作为操作系统的线程。Windows操作系统也有其移植版pthreads-win32。
http://sourceware.org/pthreads-win32/
3. 临界区属于用户模式对象,实际上这种说法并不完全正确。如果一个线程试图进入另一个线程所拥有的临界区,那么这个线程就会被置为等待状态。
而进入等待状态的唯一方法是使用线程从用户模式转入内核模式,所以追求高效的实现临界区时就是想办法避免进入等待状态下的内核模式.
例子:
test_user_sync.cpp
// test_user_sync.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <Windows.h>
#include "pthread.h"
#include <iostream>
using namespace std;
static pthread_mutex_t cs_mutex = NULL;
static pthread_barrier_t barrier = NULL;
static CRITICAL_SECTION cs;
static int32_t gCount = 0;
static int32_t gExecuteCount = 0;
static const int kThreadNum = 10;
static const int kLoopNum = 50;
void sync_func()
{
++gExecuteCount;
cout << "sync_func CurrentThreadID: " << GetCurrentThreadId()
<< " gExecuteCount: " << gExecuteCount << endl;
//1.计数器递增
//1.断言只有一个线程访问这段代码.
if(gCount)
{
cout << "gCount: " << gCount << endl;
}
assert(gCount == 0);
++gCount;
assert(gCount == 1);
//1.挂起0.1秒钟,模拟计算耗时.
Sleep(100);
//1.离开函数,计数器递减
assert(gCount == 1);
--gCount;
assert(gCount == 0);
}
void* StartPthread(void* data)
{
for(int i = 0; i < kLoopNum; ++i)
{
pthread_mutex_lock( &cs_mutex );
sync_func();
pthread_mutex_unlock( &cs_mutex );
//1.挂起0.1秒,让其他线程也有机会执行.
Sleep(100);
}
pthread_barrier_wait(&barrier);
return NULL;
}
void TestPthreadCriticalSection()
{
gExecuteCount = 0;
int res = pthread_mutex_init(&cs_mutex,NULL);
assert(res == 0);
//1.创建10个线程.
//1.包括当前线程+1
pthread_barrier_init(&barrier,NULL, kThreadNum + 1);
for(int i = 0; i< kThreadNum; ++i)
{
pthread_t t;
pthread_create(&t,NULL,StartPthread,NULL);
pthread_detach(t);
}
//1.等待其他线程执行完.
pthread_barrier_wait(&barrier);
res = pthread_mutex_destroy(&cs_mutex);
assert(res == 0);
assert(kThreadNum*kLoopNum == gExecuteCount);
}
DWORD WINAPI StartWin32Thread(PVOID pvParam)
{
for(int i = 0; i < kLoopNum; ++i)
{
EnterCriticalSection(&cs);
sync_func();
LeaveCriticalSection(&cs);
//1.挂起0.1秒,让其他线程也有机会执行.
Sleep(100);
}
return 0;
}
void TestWin32CriticalSection()
{
gExecuteCount = 0;
//1.循环锁4000避免进入等待状态
InitializeCriticalSectionAndSpinCount(&cs,4000);
HANDLE hThreads[kThreadNum];
for(int i = 0; i< kThreadNum; ++i)
{
DWORD dwThreadID;
hThreads[i] = CreateThread(NULL,0,StartWin32Thread,NULL,0,&dwThreadID);
}
DWORD rc = WaitForMultipleObjects(kThreadNum, hThreads, TRUE, INFINITE);
assert(rc == WAIT_OBJECT_0);
for(int i = 0; i< kThreadNum; ++i)
{
CloseHandle(hThreads[i]);
}
DeleteCriticalSection(&cs);
}
int _tmain(int argc, _TCHAR* argv[])
{
TestWin32CriticalSection();
system("pause");
TestPthreadCriticalSection();
system("pause");
return 0;
}
输出:
项目下载地址:
http://download.youkuaiyun.com/detail/infoworld/8461421
参考:
http://blog.sina.com.cn/s/blog_4d253de30100ymov.html
http://en.wikipedia.org/wiki/Critical_section
http://blog.youkuaiyun.com/wind19/article/details/7520860
http://www.cppblog.com/sixinquan/archive/2010/02/22/108229.html
http://blog.youkuaiyun.com/qq405180763/article/details/23919191
《Windows核心编程 第4版》