190703-3 플래그
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.
플래그
#include <windows.h>
#include <TCHAR.H>
#include <vector>
using namespace std;
struct ThreadInfo {
HANDLE hThread;
bool bRun;
HWND hwnd;
POINT pt; // 클릭한 좌표
};
vector<ThreadInfo*> threadList; // 공유변수
#pragma region MyRegion
DWORD __stdcall DrawThread(LPVOID pParam);
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
HINSTANCE g_hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
...(생략)
}
#pragma endregion
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
ThreadInfo* p;
HANDLE hThread;
static DWORD threadID;
switch (iMsg)
{
case WM_CREATE:
break;
case WM_RBUTTONDOWN:
{
}
break;
case WM_LBUTTONDOWN:
{
p = new ThreadInfo;
p->bRun = true;
p->hwnd = hwnd;
p->pt.x = LOWORD(lParam);
p->pt.y = HIWORD(lParam);
hThread = CreateThread(NULL, 0, DrawThread, p, 0, &threadID);
ThreadInfo ti = { hThread,true };
p->hThread = hThread;
threadList.push_back(p);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
for (unsigned i = 0; i < threadList.size(); i++)
CloseHandle(threadList[i]->hThread);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
int ThreadInfo2Index(const vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
for (unsigned i = 0; i < threadList.size(); i++)
if (threadList[i] == p) // 해당하는 인덱스를 찾았을 경우
return i;
return -1;
}
DWORD __stdcall DrawThread(LPVOID pParam) { // Worker 쓰레드 라고한다.
Sleep(1000); // 공유 변수를 쓰게 되면 값을 늦게 가져와서 마우스 클릭이 더 빨랐을 경우 문제가 발생한다 (같은 좌표에 그림)
ThreadInfo* p = (ThreadInfo*)pParam;
HWND hwnd = p->hwnd;
HDC hdc = GetDC(hwnd);
POINT pt = p->pt;
for (int count = 0; p->bRun && count < 5; count++)
{
for (int i = 0; i < 100; i += 5)
{
Rectangle(hdc, pt.x, pt.y, pt.x + i, pt.y + i);
Sleep(40);
}
}
ReleaseDC(hwnd, hdc);
int delIndex = ThreadInfo2Index(threadList, p);
threadList.erase(threadList.begin() + delIndex);
delete p;
return 0;
}
공유변수는 서로다른 쓰레드가 Write할 때 데이터가 더렵혀지는 현상이 발생한다. -> 동기화를 해야한다.
동기화는 따로 묶어논다. 동기화 작업만 함수로 묶어놓는다.
#include <windows.h>
#include <TCHAR.H>
#include <vector>
using namespace std;
struct ThreadInfo {
HANDLE hThread;
bool bRun;
HWND hwnd;
POINT pt; // 클릭한 좌표
};
vector<ThreadInfo*> threadList; // 공유변수
HANDLE hMutex;
#pragma region MyRegion
DWORD __stdcall DrawThread(LPVOID pParam);
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
HINSTANCE g_hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
//(생략)
}
#pragma endregion
int ThreadInfo2Index(const vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
for (unsigned i = 0; i < threadList.size(); i++)
if (threadList[i] == p) // 해당하는 인덱스를 찾았을 경우
return i;
return -1;
}
///////// Critical Section
void AddThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
WaitForSingleObject(hMutex, INFINITE);
threadList.push_back((ThreadInfo*)p); // 공유변수에 접근한다.
ReleaseMutex(hMutex);
}
void RemoveThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
WaitForSingleObject(hMutex, INFINITE);
int delIndex = ThreadInfo2Index(threadList, p);
threadList.erase(threadList.begin() + delIndex);// 인덱스 받아서 원소 제거
ReleaseMutex(hMutex);
}
/////////
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
ThreadInfo* p;
HANDLE hThread;
static DWORD threadID;
switch (iMsg)
{
case WM_CREATE:
hMutex = CreateMutex(NULL, FALSE, NULL);// 뮤텍스 생성
break;
case WM_RBUTTONDOWN:
{
}
break;
case WM_LBUTTONDOWN:
{
p = new ThreadInfo;
p->bRun = true;
p->hwnd = hwnd;
p->pt.x = LOWORD(lParam);
p->pt.y = HIWORD(lParam);
hThread = CreateThread(NULL, 0, DrawThread, p, 0, &threadID);
ThreadInfo ti = { hThread,true };
p->hThread = hThread;
AddThreadInfo(threadList, p);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
for (unsigned i = 0; i < threadList.size(); i++)
CloseHandle(threadList[i]->hThread);
CloseHandle(hMutex);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
DWORD __stdcall DrawThread(LPVOID pParam) { // Worker 쓰레드 라고한다.
ThreadInfo* p = (ThreadInfo*)pParam;
HWND hwnd = p->hwnd;
HDC hdc = GetDC(hwnd);
POINT pt = p->pt;
for (int count = 0; p->bRun && count < 5; count++)
{
for (int i = 0; i < 100; i += 5)
{
Rectangle(hdc, pt.x, pt.y, pt.x + i, pt.y + i);
Sleep(40);
}
}
ReleaseDC(hwnd, hdc);
RemoveThreadInfo(threadList, p);
delete p;
return 0;
}
c++ 꿀Tip)
// 많이 쓰는 자원 관리 클래스
class ResMutex { // 리소스 뮤텍스
HANDLE hMutex;
public:
ResMutex(HANDLE hm):hMutex(hm) {
WaitForSingleObject(hMutex, INFINITE);
}
~ResMutex() {
ReleaseMutex(hMutex);// 객체 생성시 소멸자 호출 보장하므로 ReleaseMutex() 보장
}
};
클래스를 따로지정하여 생성자를 사용하여 뮤텍스를 생성한다.
///////// Critical Section
void AddThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
ResMutex m(hMutex);
threadList.push_back((ThreadInfo*)p); // 공유변수에 접근한다.
}
void RemoveThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
ResMutex m(hMutex);
int delIndex = ThreadInfo2Index(threadList, p);
threadList.erase(threadList.begin() + delIndex);// 인덱스 받아서 원소 제거
}
/////////
장점 : 예외시 소멸자 호출이 보장된다.
플래그
#include <windows.h>
#include <TCHAR.H>
#include <vector>
using namespace std;
// 많이 쓰는 자원 관리 클래스
class ResMutex { // 리소스 뮤텍스
HANDLE hMutex;
public:
ResMutex(HANDLE hm) :hMutex(hm) {
WaitForSingleObject(hMutex, INFINITE);
}
~ResMutex() {
ReleaseMutex(hMutex);
}
};
struct ThreadInfo {
HANDLE hThread;
bool bRun;
HWND hwnd;
POINT pt; // 클릭한 좌표
};
vector<ThreadInfo*> threadList; // 공유변수
HANDLE hMutex;
void RemoveRandThreadInfo(vector<ThreadInfo*>& threadList) {
ResMutex m(hMutex); // 동기화 작업을한다. 임계영역을 설정
int exitIndex = rand() % threadList.size();
threadList[exitIndex]->bRun=false;
}
#pragma region MyRegion
DWORD __stdcall DrawThread(LPVOID pParam);
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
HINSTANCE g_hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
생략
}
#pragma endregion
int ThreadInfo2Index(const vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
for (unsigned i = 0; i < threadList.size(); i++)
if (threadList[i] == p) // 해당하는 인덱스를 찾았을 경우
return i;
return -1;
}
///////// Critical Section
void AddThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
ResMutex m(hMutex);
threadList.push_back((ThreadInfo*)p); // 공유변수에 접근한다.
}
void RemoveThreadInfo(vector<ThreadInfo*>& threadList, const ThreadInfo* p) {
ResMutex m(hMutex);
int delIndex = ThreadInfo2Index(threadList, p);
threadList.erase(threadList.begin() + delIndex);// 인덱스 받아서 원소 제거
}
/////////
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
ThreadInfo* p;
HANDLE hThread;
static DWORD threadID;
switch (iMsg)
{
case WM_CREATE:
hMutex = CreateMutex(NULL, FALSE, NULL);// 뮤텍스 생성
break;
case WM_RBUTTONDOWN:
{
RemoveRandThreadInfo(threadList);
}
break;
case WM_LBUTTONDOWN:
{
p = new ThreadInfo;
p->bRun = true;
p->hwnd = hwnd;
p->pt.x = LOWORD(lParam);
p->pt.y = HIWORD(lParam);
hThread = CreateThread(NULL, 0, DrawThread, p, 0, &threadID);
ThreadInfo ti = { hThread,true };
p->hThread = hThread;
AddThreadInfo(threadList, p);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
for (unsigned i = 0; i < threadList.size(); i++)
CloseHandle(threadList[i]->hThread);
CloseHandle(hMutex);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
DWORD __stdcall DrawThread(LPVOID pParam) { // Worker 쓰레드 라고한다.
ThreadInfo* p = (ThreadInfo*)pParam;
HWND hwnd = p->hwnd;
HDC hdc = GetDC(hwnd);
POINT pt = p->pt;
for (int count = 0; p->bRun && count < 5; count++)
{
for (int i = 0; i < 100; i += 5)
{
Rectangle(hdc, pt.x, pt.y, pt.x + i, pt.y + i);
Sleep(40);
}
}
ReleaseDC(hwnd, hdc);
RemoveThreadInfo(threadList, p);
delete p;
return 0;
}
리스트의 사이즈를 가져와서 랜덤으로 제거하는데 그 연산을 임계영역으로 지정하여 수행한다.
#include <windows.h>
#include <TCHAR.H>
struct TP {
LPTSTR str; //== THAR*
int x;
int y;
};
HWND gHwnd;
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
생략
}
//Thread Function
DWORD __stdcall TF(LPVOID param) {
const TP* tp = (const TP*)param;
HDC dc = GetDC(gHwnd);
TextOut(dc, tp->x, tp->y, tp->str, lstrlen(tp->str));
ReleaseDC(gHwnd, dc);
delete tp; // 동적으로 할당받은 heap메모리를 해제한다.
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
HANDLE hThread;
DWORD id;
TP* p;
switch (iMsg)
{
case WM_CREATE:
gHwnd = hwnd;
break;
case WM_LBUTTONDOWN:
p = new TP();//쓰레드 파라미터를 힙메모리에 생성후
p->str = (LPTSTR)_T("Hello!");
p->x = LOWORD(lParam);
p->y = HIWORD(lParam);
hThread = CreateThread(NULL, 0, TF, p, 0, &id);//p로 전달해서 사용한다.
CloseHandle(hThread);// 핸들을 사용하지 않을거라 핸들반환
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
'System Programming' 카테고리의 다른 글
[system programming] CHECKER3.C -- Mouse Hit-Test Demo Program No. 3 (0) | 2019.07.05 |
---|---|
[system programming] IPC 메세지, COPYDATASTRUCT (0) | 2019.07.05 |
[system programming] 유저, 커널모드 동기화 (크리티컬 섹션, 뮤텍스, 세마포어, 이벤트 등) (0) | 2019.07.05 |
[system programming] __declspec(thread) (0) | 2019.07.05 |
[system programming] 핸들, 커널 오브젝트, 프로세스 등 (0) | 2019.07.04 |