关键部分CCriticalSection使用

CCriticalSection是Windows API提供的一个同步对象,用于保护共享资源的访问,常用于多线程编程中。使用CCriticalSection可以确保同一时刻只有一个线程能够访问被保护的共享资源,从而避免资源冲突、数据竞争等问题。本文将详细介绍CCriticalSection的使用方法,并提供多个实际应用案例以便读者对其理解更加深刻。

使用方法:

1. 定义CCriticalSection对象

在使用CCriticalSection之前,需要先定义一个CCriticalSection对象。定义方式如下:

CCriticalSection cs;

2. 进入临界区

在访问共享资源之前,需要先进入临界区。进入临界区时,需要调用CCriticalSection类的Lock()函数。如果Lock()函数返回true,则表示已成功进入临界区,否则需要等待临界区内的其他线程执行完后才能进入。

cs.Lock();

3. 访问共享资源

进入临界区后就可以访问共享资源了。此时,其他线程不能访问共享资源,直到当前线程执行完毕并退出临界区。

// 访问共享资源的代码

4. 离开临界区

完成对共享资源的访问后,需要离开临界区。离开临界区时,需要调用CCriticalSection类的Unlock()函数。如果成功离开临界区,则其他线程可以进入临界区并访问共享资源。

cs.Unlock();

案例说明:

1. 多线程计算器

一个典型的使用CCriticalSection的案例是多线程计算器。多线程计算器可以利用多个线程各自计算子任务,最后汇总结果以提高计算效率。这里以计算1~1000的所有整数和为例,使用两个线程同时计算,每个线程计算500个整数。具体代码如下:

class CCalculator

{

public:

CCalculator() {}

~CCalculator() {}

void SetRange(int nStart, int nEnd)

{

m_nStart = nStart;

m_nEnd = nEnd;

}

int GetResult() const

{

return m_nResult;

}

void Calculate()

{

m_nResult = 0;

for (int i = m_nStart; i <= m_nEnd; ++i)

{

m_nResult += i;

}

}

private:

int m_nStart; // 起始值

int m_nEnd; // 结束值

int m_nResult; // 结果

};

void ThreadProc1(LPVOID lpParam)

{

CCalculator* pCalc = (CCalculator*)lpParam;

pCalc->SetRange(1, 500);

pCalc->Calculate();

}

void ThreadProc2(LPVOID lpParam)

{

CCalculator* pCalc = (CCalculator*)lpParam;

pCalc->SetRange(501, 1000);

pCalc->Calculate();

}

int MyMultiThreadCalculator()

{

CCalculator calc1, calc2;

// 创建线程1

DWORD dwThreadId1;

HANDLE hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, &calc1, 0, &dwThreadId1);

if (hThread1 == NULL)

{

return 0;

}

// 创建线程2

DWORD dwThreadId2;

HANDLE hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, &calc2, 0, &dwThreadId2);

if (hThread2 == NULL)

{

return 0;

}

// 等待线程结束

WaitForSingleObject(hThread1, INFINITE);

WaitForSingleObject(hThread2, INFINITE);

// 汇总结果

int nResult = calc1.GetResult() + calc2.GetResult();

return nResult;

}

在ThreadProc1和ThreadProc2中分别创建一个CCalculator对象,分别计算1~500和501~1000的所有整数和。由于两个线程访问了同一个共享变量m_nResult,因此需要使用CCriticalSection保护它。在CCalculator类中定义一个CCriticalSection对象,进入临界区、访问共享资源、离开临界区的代码分别为:

class CCalculator

{

public:

// ...

void Calculate()

{

m_cs.Lock(); // 进入临界区

for (int i = m_nStart; i <= m_nEnd; ++i)

{

m_nResult += i;

}

m_cs.Unlock(); // 离开临界区

}

private:

int m_nStart; // 起始值

int m_nEnd; // 结束值

int m_nResult; // 结果

CCriticalSection m_cs; // 临界区保护共享变量

};

2. 多线程网络通信

另一个实际应用CCriticalSection的案例是多线程网络通信。在一个多线程网络应用中,多个线程同时向网络发送数据和接收数据,这些线程都会访问同一套接字(socket),因此需要使用CCriticalSection保护套接字的访问。具体代码如下:

// 全局变量,用于保存套接字

SOCKET g_socket = INVALID_SOCKET;

// 发送数据

void SendData(const char* pBuffer, int nLen)

{

CCriticalSection cs;

cs.Lock();

int nBytesSent = send(g_socket, pBuffer, nLen, 0);

cs.Unlock();

}

// 接收数据

int ReceiveData(char* pBuffer, int nLen)

{

CCriticalSection cs;

cs.Lock();

int nBytesReceived = recv(g_socket, pBuffer, nLen, 0);

cs.Unlock();

return nBytesReceived;

}

在SendData和ReceiveData函数中,均使用CCriticalSection保护套接字的访问,避免多个线程同时访问套接字从而导致数据错误。注意,在使用CCriticalSection保护资源通信的时候,不同的线程要使用同一个CCriticalSection才能保证正确性。

总结:

本文详细介绍了CCriticalSection的使用方法,并提供了两个实际应用案例。在使用CCriticalSection时需要注意:

1. 不要重复进入临界区,否则会导致死锁的发生;

2. 尽量减小临界区的范围,否则会影响程序性能;

3. 确保所有线程使用同一个CCriticalSection,否则将会产生意想不到的结果;

4. 使用CCriticalSection之前,应先进行初始化,可以使用构造函数或InitializeCriticalSection函数进行初始化;

5. CCriticalSection是一种简单而实用的同步对象,但在多线程编程中仍需谨慎使用,结合实际情况进行合理的使用。 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.37seo.cn/

点赞(10) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部