티스토리 뷰
728x90
NONAME을 이용한 멀티스레드 세이프한 방법
1. 멀티스레드 환경에서 발생할 수 있는 문제
- 동시 접근 문제: 여러 스레드가 동일한 자원에 동시에 접근할 경우, 데이터 불일치 또는 충돌이 발생할 수 있습니다.
- 메모리 관리 문제: 객체의 생성과 해제를 DLL 내부에서 처리하지 않으면 메모리 누수나 충돌이 발생할 수 있습니다.
- 전역 변수 사용: 전역 변수에 여러 스레드가 접근할 경우 동기화가 필요합니다.
2. 스레드 안전성을 확보하는 방법
- 객체의 독립성 유지: 각 스레드가 독립적으로 객체를 사용하고, 공유 자원에 접근할 때는 동기화를 적용합니다.
- 동기화 메커니즘 사용:
mutex
,critical section
등 동기화 메커니즘을 사용하여 스레드 간 충돌을 방지합니다. - DLL 내부에서 객체 관리: 객체의 생성과 해제를 DLL 내부에서 처리하여 일관된 메모리 관리가 가능합니다.
3. 예제 코드
1) DLL 내 클래스 정의 및 스레드 안전성 확보
먼저, DLL 내부에서 클래스를 정의하고, mutex를 사용하여 스레드 안전성을 보장합니다.
// MyDLL.cpp
#include <windows.h>
#include <iostream>
#include <mutex>
// 전역 뮤텍스 선언 (스레드 동기화를 위한)
std::mutex g_mutex;
// 간단한 클래스 A 정의
class A {
public:
A() {
std::cout << "A 생성자 호출됨!" << std::endl;
}
~A() {
std::cout << "A 소멸자 호출됨!" << std::endl;
}
void DoSomething() {
std::cout << "A::DoSomething 호출됨!" << std::endl;
}
};
// 클래스 포인터 반환 함수
extern "C" __declspec(dllexport) A* CreateClassA() {
std::lock_guard<std::mutex> lock(g_mutex); // 스레드 동기화
return new A();
}
// 클래스 포인터 해제 함수
extern "C" __declspec(dllexport) void DeleteClassA(A* pA) {
std::lock_guard<std::mutex> lock(g_mutex); // 스레드 동기화
delete pA;
}
2) DEF 파일 설정 (NONAME 방식으로 export)
DLL의 DEF
파일을 사용하여 함수 이름 대신 Ordinal 값으로 함수들을 export합니다.
LIBRARY MyDLL
EXPORTS
CreateClassA @1 NONAME
DeleteClassA @2 NONAME
3) 멀티스레드 애플리케이션에서 DLL 호출
멀티스레드 환경에서 DLL의 클래스를 호출하고, 각 스레드가 안전하게 클래스를 사용한 후 해제하는 코드입니다.
// main.cpp
#include <windows.h>
#include <iostream>
#include <thread>
class A;
typedef A* (*CreateClassA)();
typedef void (*DeleteClassA)(A*);
// 스레드에서 실행될 함수
void threadFunction(CreateClassA createClassA, DeleteClassA deleteClassA) {
A* pA = createClassA(); // 클래스 A의 인스턴스 생성
if (pA) {
pA->DoSomething(); // 스레드에서 클래스 A의 메서드 호출
deleteClassA(pA); // 클래스 A의 인스턴스 해제
}
}
int main() {
// DLL 로드
HMODULE hModule = LoadLibrary("MyDLL.dll");
if (!hModule) {
std::cerr << "DLL 로드 실패" << std::endl;
return 1;
}
// Ordinal 값으로 함수 가져오기
CreateClassA createClassA = (CreateClassA)GetProcAddress(hModule, MAKEINTRESOURCE(1)); // @1
DeleteClassA deleteClassA = (DeleteClassA)GetProcAddress(hModule, MAKEINTRESOURCE(2)); // @2
if (createClassA && deleteClassA) {
// 5개의 스레드를 생성하고 각각 클래스 A 인스턴스를 생성하고 사용
std::thread threads[5];
for (int i = 0; i < 5; ++i) {
threads[i] = std::thread(threadFunction, createClassA, deleteClassA);
}
// 모든 스레드 종료 대기
for (auto& th : threads) {
th.join();
}
}
// DLL 언로드
FreeLibrary(hModule);
return 0;
}
4. 보안 및 관리 측면
- 메모리 관리: 객체의 생성과 해제를 DLL 내부에서 처리하여 메모리 충돌과 누수를 방지할 수 있습니다.
- 스레드 안전성: 동기화 메커니즘을 사용하여 여러 스레드가 동시에 DLL 자원에 접근할 때도 안전하게 동작합니다.
- 보안 강화: NONAME 기술을 사용하여 함수 이름 대신 Ordinal 값으로 접근함으로써 함수 이름을 숨기고 보안을 강화할 수 있습니다.
5. 결론
NONAME 기술을 사용하여 DLL에서 멀티스레드 환경에서도 안전하게 클래스를 생성하고 관리할 수 있습니다. 동기화 메커니즘을 통해 스레드 간 충돌을 방지하고, 메모리 관리를 DLL 내부에서 처리하여 메모리 누수를 방지합니다. 이 방법은 보안을 중요시하는 환경에서 효과적일 수 있습니다.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 서귀포블루버블
- C++
- OpenSource
- Effective c++
- 현포다이브
- Windows
- 스쿠버다이빙
- C
- DLL
- 스쿠버 다이빙
- C#.NET
- 제주도
- 블루버블다이브팀
- Build
- C# 고급 기술
- effective
- Linux
- script
- CMake
- 울릉도
- 외돌개
- 성산블루버블
- 블루버블다이빙팀
- PowerShell
- 암호화
- 네트워크 정보
- 블루버블
- C#
- 서귀포
- 패턴
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함
250x250