最近看的书中介绍了线程临界区同步方式,思考之前写过的内存释放相关结构便动手实现一个简易的临界区(支持多个线程同时使用)。
关于结构设计的几点介绍:
1.设计采用了先进先出概念,当第一个线程进入临界区后,别的线程需要在临界区等待,临界区释放后下一个线程才能进入临界区;
2.设计采用了递增进入方式,比如第一个线程为0顺序,第二个线程为1顺序等等以此类推;
3.设计采用了轻量级参数,结构安全性比较高,不会出现崩溃情况(按正常临界区方式操作,每次线程退出前需要释放临界区,防止造成死锁)。
函数定义如下:
void TestInitializeCriticalSection(pTestCritical obj);/* 初始化函数实际用处不大稳定考虑在构造函数已经初始化,可以不用 */
void TestEnterCriticalSection(pTestCritical obj);//加载临界区
void TestLeaveCriticalSection(pTestCritical obj);//释放临界区
typedef struct TestCritical//临界区结构体
{
TestCritical():nCritical(0),nCount(0)
{
}
volatile int nCritical;/* 临界区运行标志 ,0表示没有进入临界区 ,1 表示进入临界区 */
volatile int nCount;/* 临界区等待进入的顺序计数 */
}*pTestCritical;
代码实现如下:
void TestInitializeCriticalSection(pTestCritical obj)/* 初始化函数实际用处不大稳定考虑在构造函数已经初始化,可以不用 */
{
while (1 == obj->nCritical) /* 如果临界区已经运行那么初始化失败 */
return ;
obj->nCritical = 0;
}
void TestEnterCriticalSection(pTestCritical obj)//加载临界区
{
int nCount = obj->nCount;/*获取到等待顺序,如果为0为第一个等待进入临界区*/
obj->nCount++;//这里说明下多个线程情况下可能会造成nCount增加慢了一步,不过没有影响 数据一切正常
while (0 != obj->nCritical || (0 != nCount && nCount != obj->nCount))
;
obj->nCritical = 1;
}
void TestLeaveCriticalSection(pTestCritical obj)//释放临界区
{
if (0 == obj->nCritical)
{
return;
}
obj->nCritical = 0;
obj->nCount--;
}
使用方式(测试方法):
AfxBeginThread(TestCriticalThread,this);
AfxBeginThread(TestCriticalThread2,this);
AfxBeginThread(TestCriticalThread,this);
UINT TestCriticalThread(LPVOID _this)
{
CTestSTLFileDlg* testDlg = (CTestSTLFileDlg*)_this;
TestEnterCriticalSection(&test);
Sleep(100);
for (int i = 0;i < 10;i++)
testDlg->TestData[i] = i;
TestLeaveCriticalSection(&test);
return 0;
}
UINT TestCriticalThread2(LPVOID _this)
{
CTestSTLFileDlg* testDlg = (CTestSTLFileDlg*)_this;
TestEnterCriticalSection(&test);
for (int i = 10;i < 20;i++)
testDlg->TestData[i] = i;
TestLeaveCriticalSection(&test);
return 0;
}
最近和朋友讨论了一下关与原子量以及计数器的执行原理,应该是通过对硬件的直接操作(比如调用中断达到硬件上的支持)完成计数器的自增或者自减的完成。