ccriticalsection 用法 为什么是未定义标识符

ccriticalsection 用法 为什么是未定义标识符,第1张

CCriticalSection是对关键段CRITICAL_SECTION的封装。

关键段(critival section)是一小段代码,他在执行之前需要独占对一些共享资源的访问权。这种方式可以让多行代码以“原子方式”来对资源进行 *** 控。这里的“原子方式”,指的是代码知道除了当前线程之外没有其他任何线程会同时访问该资源。当然,系统仍然可以暂停当前线程去调度其他线程。但是,在当前线程离开关键段之前,系统是不会去调度任何想要访问同一资源的其他线程的。

例如:如果两个线程同时访问一个链表,一个线程可能会在另一个线程搜寻元素的同时向链表中添加一个元素,将导致搜索结果不正确;还有可能两个线程同时向链表中添加元素,这种情况会变的更加混乱;甚至一个线程搜索的时候,另一个线程删除了链表节点,将直接导致程序崩溃。

解决这个问题,我们可以先在代码中定义一个CRITICAL_SECTION数据结构m_sect,然后把任何需要访问共享资源的代码放在EnterCriticalSection和LeaveCriticalSection之间。

[cpp] view plain copy print?

EnterCriticalSection(&m_sect)

// 共享资源的代码段....

LeaveCriticalSection(&m_sect)

一个 CRITICAL_SECTION结构就像是飞机上的一个卫生间,而马桶则是我们想要保护的资源(用EnterCriticalSection和LeaveCriticalSection组成的围墙包围住“马桶”)。由于卫生间很小,因此在同一时刻只允许一个人在卫生间内使用马桶(在同一时刻只允许一个线程在关键段中使用被保护资源)。

如果有多个总是应该在一起使用的资源,那么我们可以把他们放在同一个“卫生间”中:只需要创建一个CRITICAL_SECTION结构来保护所有这些资源。

关于关键段,需要掌握以下几点:

1、任何要访问共享资源的代码,都必须包含在EnterCriticalSection和LeaveCriticalSection之间。如果忘了哪怕是一个地方,共享资源就有可能被破坏。忘记调用EnterCriticalSection和LeaveCriticalSection,就好像是未经许可就强制进入卫生间一样,线程强行进入并对资源进行 *** 控。只要有一个线程有这种粗暴的行为,资源就会被破坏。

2、关键段CRITICAL_SECTION是个未公开的结构,因为Microsoft认为开发人员不需要理解这个结构的细节。对我们来说,不需要知道这个结构中的成员变量,我们绝对不应该在编写代码的时候用到他的成员。

3、为了对CRITICAL_SECTION结构进行 *** 控,我们必须调用Windows API函数,传入结构的地址。(注意是地址!)也就是说,如果该CRITICAL_SECTION结构生命周期没有结束,那么可以将该结构地址通过自己喜欢的任何方式传给任何线程。

4、在任何线程试图访问被保护的资源之前,必须对CRITICAL_SECTION结构的内部成员进程初始化。我们不知道内部成员,但可以调用Windows函数实现:VOID WINAPI InitializeCriticalSection(__out LPCRITICAL_SECTION lpCriticalSection)

5、当线程不再需要访问共享资源的时候,应调用下面的函数来清理该结构:VOID WINAPI DeleteCriticalSection(__inout LPCRITICAL_SECTION lpCriticalSection)

6、其实CRITICAL_SECTION并不知道什么是共享资源,也不会智能保护共享资源。其根本是,同一个时刻如果有多个线程调用EnterCriticalSection的时候,只有一个线程返回,其余线程则暂停执行,等待前面线程调用LeaveCriticalSection之后再执行。

7、可以看出,进入关键段是没有超时设定的,好像永远不会超时。实际上,对EnterCriticalSection的调用也会超时并引发异常。超时的时间长度由下面这个注册表子项中包含的CriticalSectionTimeout值决定:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager

这个值以秒为单位,他的默认值为2592000秒,大约30天。

8、同一个线程可以随便进入用一个关键段N次,也就是说同一个线程调用EnterCriticalSection无论几次都会返回。不同线程是否能够进入关键段,要看EnterCriticalSection的参数(CRITICAL_SECTION结构的地址)之前是否有线程进入过。要记住:飞机上的卫生间有多个,你可以随便进入无人的卫生间,不能进入有人的卫生间。

弄明白了CRITICAL_SECTION之后,使用CCriticalSection非常方便,如虎添翼。看代码:

//头文件

[cpp] view plain copy print?

class CCriticalSection : public CSyncObjet

{...

public:

CRITICAL_SECTION m_sect

public:

BOOL Unlock()

BOOL Lock()

BOOL Lock(DWORD dwTimeout)

...

}

// 构造函数

[cpp] view plain copy print?

CCriticalSection::CCriticalSection() : CSyncObject(NULL)

{

HRESULT hr = S_OK

if (!InitializeCriticalSectionAndSpinCount(&m_sect, 0))//可以理解为InitializeCriticalSection,为了效率,加了一个旋转锁。

{

hr = HRESULT_FROM_WIN32(GetLastError())

}

if (FAILED(hr))

{

AtlThrow(hr)

}

}

//进入关键段

[cpp] view plain copy print?

BOOL CCriticalSection::Lock()

{

::EnterCriticalSection(&m_sect)

return TRUE

}

// 离开关键段

[cpp] view plain copy print?

BOOL CCriticalSection::Unlock()

{

::LeaveCriticalSection(&m_sect)

return TRUE

}

// 析构

[cpp] view plain copy print?

CCriticalSection::~CCriticalSection()

{

::DeleteCriticalSection(&m_sect)

}

系统学习Windows客户端开发

在某些业务场景下希望截全屏时不显示某些窗口特别是自身应用的窗口,比如在屏幕共享时不希望将自己应用的主界面、工具条等共享给对方。

Windows有个特性Magnification(放大镜)特性,它允许将屏幕(或屏幕某个指定区域)进行放大,如果不设置放大比例等同于截屏,其支持选择窗口过滤,利用该特性就可以实现过滤部分窗口下截屏。该特性从Vista开始支持,如果产品需要支持Win XP系统就不能使用该方案。

使用Magnification进行截屏的流程如下:

笔者编写类CScreenCapture,用来实现过滤部分窗口截图,结合MSDN仔细阅读理解就容易掌握其使用。CScreenCapture类提供三个接口SetFilterWindowList()指定过滤窗口列表,SetFrameRate()指定每秒帧数,SetScreenImageArriveCallback()设置回调接收图片。内部开启一个UI线程定期执行截屏,线程创建运行使用 一个简单实用的线程基类CThreadBase,最后DEMO演示如何在接收图片回调中将其保存成BITMAP格式的图片。

类CScreenCapture头文件

#pragma once

#include <Magnification.h>

#include <vector>

#include <map>

#include "ThreadBase.h"

class IScreenImageArriveCallback

{

public:

// called when screen was captured

// param is same as MagImageScalingCallback

virtual void OnScreenImageArriveCallback(MAGIMAGEHEADER srcheader, void *srcdata) = 0

}

class CScreenCapturer : public CThreadBase

{

public:

CScreenCapturer()

~CScreenCapturer()

public:

// set the callback of screen image arrived

void SetScreenImageArriveCallback(IScreenImageArriveCallback* pCallback)

// set filter window list that will not show on the screen image

void SetFilterWindowList(const std::vector<HWND>&vecFilterWindow)

// frame rate represent times of capturing screen per second

bool SetFrameRate(unsigned int nFrameRate)

protected: // override CThreadBase

virtual bool OnStart(const std::string&strParam) override

virtual void OnRun(const std::string&strParam) override

virtual void OnStop() override

private:

static BOOL MagImageScaling(HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty)

static LRESULT CALLBACK MsgWndWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

void CaptureScreen()

private:

CRITICAL_SECTION m_syncObject

DWORD m_nThreadId = 0

HWND m_hwndMagnification = NULL

RECT m_rectScreen

IScreenImageArriveCallback* m_pScreenImageArriveCallback = nullptr

HWND* m_pFilterWindows = nullptr

unsigned int m_nFilterWindowsCount = 0

unsigned int m_nFrameRate = 15

}

复制

类CScreenCapture源文件

#include "ScreenCapturer.h"

#pragma comment(lib, "Magnification.lib")

#define WINDOW_CLASS_NAME L"magnification_host"

#define TIMER_ID_CAPTURE_SCREEN 100

CScreenCapturer::CScreenCapturer()

{

InitializeCriticalSection(&m_syncObject)

}

CScreenCapturer::~CScreenCapturer()

{

if (m_pFilterWindows)

{

delete[] m_pFilterWindows

m_pFilterWindows = nullptr

}

DeleteCriticalSection(&m_syncObject)

}

void CScreenCapturer::SetScreenImageArriveCallback(IScreenImageArriveCallback* pCallback)

{

m_pScreenImageArriveCallback = pCallback

}

void CScreenCapturer::SetFilterWindowList(const std::vector<HWND>&vecFilterWindow)

{

EnterCriticalSection(&m_syncObject)

m_nFilterWindowsCount = vecFilterWindow.size()

if (m_pFilterWindows)

{

delete[] m_pFilterWindows

m_pFilterWindows = nullptr

}

if (m_nFilterWindowsCount >0)

{

m_pFilterWindows = new HWND[m_nFilterWindowsCount]

for (unsigned int i = 0i <m_nFilterWindowsCounti++)

{

m_pFilterWindows[i] = vecFilterWindow[i]

}

}

LeaveCriticalSection(&m_syncObject)

}

bool CScreenCapturer::SetFrameRate(unsigned int nFrameRate)

{

if (nFrameRate == 0 || nFrameRate >60)

{

return false

}

m_nFrameRate = nFrameRate

return true

}

bool CScreenCapturer::OnStart(const std::string&strParam)

{

return true

}

void CScreenCapturer::OnRun(const std::string&strParam)

{

m_nThreadId = GetCurrentThreadId()

// Init magnification

if (!MagInitialize())

{

return

}

// Register magnification host window class

WNDCLASS wc = { 0 }

wc.lpszClassName = WINDOW_CLASS_NAME

wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255))

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION)

wc.hCursor = LoadCursor(NULL, IDC_ARROW)

wc.lpfnWndProc = MsgWndWindowProc

wc.hInstance = NULL

if (RegisterClass(&wc) == 0 &&GetLastError() != ERROR_CLASS_ALREADY_EXISTS)

{

return

}

// Get screen resolution

HWND hDesktop = ::GetDesktopWindow()

::GetWindowRect(hDesktop, &m_rectScreen)

int nScreenX = m_rectScreen.right - m_rectScreen.left

int nScreenY = m_rectScreen.bottom - m_rectScreen.top

// Create host window

HWND hHostWindow = CreateWindowEx(WS_EX_LAYERED, WINDOW_CLASS_NAME, L"", WS_POPUP, 0, 0, nScreenX, nScreenY, GetDesktopWindow(), 0, NULL, 0)

if (hHostWindow == NULL)

{

return

}

SetLayeredWindowAttributes(hHostWindow, 0, 255, LWA_ALPHA)

SetWindowLong(hHostWindow, GWL_USERDATA, (LONG_PTR)this)

// Create magnification window

m_hwndMagnification = CreateWindow(WC_MAGNIFIER, L"MagnifierWindow", WS_CHILD | WS_VISIBLE, 0, 0, nScreenX, nScreenY, hHostWindow, NULL, NULL, NULL)

if (m_hwndMagnification == NULL)

{

DestroyWindow(hHostWindow)

return

}

// Set capture callback

if (!MagSetImageScalingCallback(m_hwndMagnification, (MagImageScalingCallback)&CScreenCapturer::MagImageScaling))

{

DestroyWindow(hHostWindow)

return

}

// Set timer to capture screen

SetTimer(hHostWindow, TIMER_ID_CAPTURE_SCREEN, 1000/m_nFrameRate, nullptr)

MSG msg

while (GetMessage(&msg, 0, 0, 0))

{

DispatchMessage(&msg)

}

KillTimer(hHostWindow, TIMER_ID_CAPTURE_SCREEN)

DestroyWindow(hHostWindow)

m_hwndMagnification = NULL

}

void CScreenCapturer::OnStop()

{

if (m_nThreadId >0)

{

PostThreadMessage(m_nThreadId, WM_QUIT, 0, 0)

m_nThreadId = 0

}

}

BOOL CScreenCapturer::MagImageScaling(HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty)

{

HWND hParent = hwnd

while (true)

{

hParent = GetParent(hParent)

if (hParent == NULL)

{

break

}

wchar_t szClassName[200]

memset(szClassName, 0, sizeof(szClassName))

GetClassName(hParent, szClassName, 200)

if (wcscmp(szClassName, WINDOW_CLASS_NAME) == 0)

{

break

}

}

if (hParent == NULL)

{

return TRUE

}

CScreenCapturer* pScreenCapture = (CScreenCapturer*)GetWindowLong(hParent, GWL_USERDATA)

if (pScreenCapture &&pScreenCapture->m_pScreenImageArriveCallback)

{

pScreenCapture->m_pScreenImageArriveCallback->OnScreenImageArriveCallback(srcheader, srcdata)

}

return TRUE

}

LRESULT CALLBACK CScreenCapturer::MsgWndWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

if (message == WM_TIMER &&wParam == TIMER_ID_CAPTURE_SCREEN)

{

CScreenCapturer* pScreenCapture = (CScreenCapturer*)GetWindowLong(hWnd, GWL_USERDATA)

if (pScreenCapture)

{

pScreenCapture->CaptureScreen()

}

return 0L

}

return DefWindowProc(hWnd, message, wParam, lParam)

}

void CScreenCapturer::CaptureScreen()

{

EnterCriticalSection(&m_syncObject)

MagSetWindowFilterList(m_hwndMagnification, MW_FILTERMODE_EXCLUDE, m_nFilterWindowsCount, m_pFilterWindows)

LeaveCriticalSection(&m_syncObject)

MagSetWindowSource(m_hwndMagnification, m_rectScreen)

}

复制

接收图片回调中保存成BITMAP格式的图片

void CMFCApplicationDlg::OnScreenImageArriveCallback(MAGIMAGEHEADER srcheader, void *srcdata)

{

// construct bitmap

BITMAPINFOHEADER bmif

bmif.biSize = sizeof(BITMAPINFOHEADER)

bmif.biHeight = srcheader.height

bmif.biWidth = srcheader.width

bmif.biSizeImage = bmif.biWidth*bmif.biHeight * 4

bmif.biPlanes = 1

bmif.biBitCount = (WORD)(bmif.biSizeImage / bmif.biHeight / bmif.biWidth * 8)

bmif.biCompression = BI_RGB

BITMAPFILEHEADER bmfh

LONG offBits = sizeof(BITMAPFILEHEADER) + bmif.biSize

bmfh.bfType = 0x4d42// "BM"

bmfh.bfOffBits = offBits

bmfh.bfSize = offBits + bmif.biSizeImage

bmfh.bfReserved1 = 0

bmfh.bfReserved2 = 0

// 返回的图片数据存储是从上到下,位图要求是从下到上,所以需要调整

LPBYTE pData = (BYTE*)new BYTE[bmif.biSizeImage]

memcpy(pData, (LPBYTE)srcdata+srcheader.offset, bmif.biSizeImage)

LONG nLineSize = bmif.biWidth * bmif.biBitCount / 8

BYTE* pLineData = new BYTE[nLineSize]

LONG nLineStartIndex = 0

LONG nLineEndIndex = bmif.biHeight - 1

while (nLineStartIndex <nLineEndIndex)

{

BYTE* pStart = pData + (nLineStartIndex * nLineSize)

BYTE* pEnd = pData + (nLineEndIndex * nLineSize)

memcpy(pLineData, pStart, nLineSize)

memcpy(pStart, pEnd, nLineSize)

memcpy(pEnd, pLineData, nLineSize)

nLineStartIndex++

nLineEndIndex--

}

delete[] pLineData

pLineData = nullptr

std::ofstream ofs(L"C:\\1.bmp", fstream::out|fstream::binary)

if (ofs.is_open())

{

ofs.write((const char*)&bmfh, sizeof(BITMAPFILEHEADER))

ofs.write((const char*)&bmif, sizeof(BITMAPINFOHEADER))

ofs.write((const char*)pData, bmif.biSizeImage)

ofs.close()

}

delete[] pData

pData = nullptr

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/11893112.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存