티스토리 뷰
728x90
CFileMon 클래스 설계 및 구현
개요
CFileMon 클래스는 특정 파일의 변경 사항을 감지하며, Windows와 POSIX 환경 모두에서 작동하도록 설계되었습니다. Named Mutex를 활용하여 다중 프로세스 동기화를 보장하며, 파일이 삭제되거나 수정되는 상황에 안정적으로 대응합니다.
주요 기능
- Windows 및 POSIX 환경 지원
- Named Mutex를 활용하여 다중 프로세스 동기화
- 파일 변경 시 해시를 비교하여 변경 여부 감지
- 파일이 삭제되거나 접근 불가한 경우 예외 처리
- 주기적인 파일 상태 확인 (스레드 기반 구현)
플랫폼별 구현
Windows
- Named Mutex를
CreateMutexA
로 생성 WaitForSingleObject
와ReleaseMutex
로 동기화 관리- 파일 존재 확인은
std::filesystem::exists
사용
POSIX
- Named Mutex는
pthread_mutex
와shm_open
으로 구현 - 공유 메모리를 사용해 다중 프로세스 간 동기화 관리
- 파일 존재 확인은
stat
API 사용
코드
아래는 Windows와 POSIX 환경 모두를 지원하는 CFileMon
클래스의 구현 예제입니다:
#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
#include <stdexcept>
#ifdef _WIN32
#include <windows.h>
#include <filesystem>
#include <openssl/sha.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <openssl/sha.h>
#endif
class CFileMon {
public:
CFileMon(const std::string& filePath, const std::string& mutexName, int intervalMs)
: filePath(filePath), mutexName(mutexName), intervalMs(intervalMs), stopFlag(false) {
#ifdef _WIN32
hMutex = CreateMutexA(nullptr, FALSE, mutexName.c_str());
if (hMutex == nullptr) {
throw std::runtime_error("Failed to create mutex");
}
#else
shmFd = shm_open(mutexName.c_str(), O_CREAT | O_RDWR, 0666);
if (shmFd < 0) {
throw std::runtime_error("Failed to create shared memory");
}
ftruncate(shmFd, sizeof(pthread_mutex_t));
sharedMutex = static_cast<pthread_mutex_t*>(mmap(nullptr, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0));
if (sharedMutex == MAP_FAILED) {
throw std::runtime_error("Failed to map shared memory");
}
pthread_mutexattr_init(&mutexAttr);
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(sharedMutex, &mutexAttr);
#endif
}
~CFileMon() {
stopMonitoring();
#ifdef _WIN32
if (hMutex) CloseHandle(hMutex);
#else
if (sharedMutex) {
pthread_mutex_destroy(sharedMutex);
munmap(sharedMutex, sizeof(pthread_mutex_t));
}
if (shmFd >= 0) {
close(shmFd);
shm_unlink(mutexName.c_str());
}
pthread_mutexattr_destroy(&mutexAttr);
#endif
}
void startMonitoring() {
stopFlag = false;
monitorThread = std::thread(&CFileMon::monitorFile, this);
}
void stopMonitoring() {
stopFlag = true;
if (monitorThread.joinable()) monitorThread.join();
}
private:
std::string filePath, mutexName;
int intervalMs;
std::atomic<bool> stopFlag;
std::thread monitorThread;
std::string lastHash;
std::mutex localMutex;
#ifdef _WIN32
HANDLE hMutex;
#else
int shmFd;
pthread_mutex_t* sharedMutex;
pthread_mutexattr_t mutexAttr;
#endif
std::string calculateHash(const std::string& filePath) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) throw std::runtime_error("File cannot be opened");
SHA256_CTX sha256;
SHA256_Init(&sha256);
char buffer[4096];
while (file.good()) {
file.read(buffer, sizeof(buffer));
SHA256_Update(&sha256, buffer, file.gcount());
}
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_Final(hash, &sha256);
std::ostringstream result;
for (unsigned char c : hash) {
result << std::hex << std::setw(2) << std::setfill('0') << (int)c;
}
return result.str();
}
void monitorFile() {
while (!stopFlag) {
#ifdef _WIN32
if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
#else
if (pthread_mutex_lock(sharedMutex) == 0) {
#endif
std::lock_guard<std::mutex> lock(localMutex);
#ifdef _WIN32
if (std::filesystem::exists(filePath)) {
#else
struct stat buffer;
if (stat(filePath.c_str(), &buffer) == 0) {
#endif
std::string currentHash = calculateHash(filePath);
if (lastHash != currentHash) {
lastHash = currentHash;
onFileChanged();
}
} else {
onFileDeleted();
}
#ifdef _WIN32
ReleaseMutex(hMutex);
#else
pthread_mutex_unlock(sharedMutex);
#endif
}
std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs));
}
}
void onFileChanged() {
std::cout << "File changed! Reading file...\n";
}
void onFileDeleted() {
std::cout << "File deleted or not accessible. Waiting for recreation...\n";
}
};
int main() {
const std::string filePath = "example.txt";
const std::string mutexName = "CFileMonMutex";
const int intervalMs = 1000;
try {
CFileMon fileMonitor(filePath, mutexName, intervalMs);
fileMonitor.startMonitoring();
std::this_thread::sleep_for(std::chrono::seconds(10));
fileMonitor.stopMonitoring();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
}
return 0;
}
결론
CFileMon 클래스는 Named Mutex를 사용해 Windows와 POSIX 환경에서 안정적인 파일 모니터링을 제공합니다. 이 코드를 기반으로 다중 프로세스 간 안전한 파일 접근을 구현할 수 있습니다.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- C++
- DLL
- C# 고급 기술
- PowerShell
- Thread
- 리눅스
- 암호화
- 외돌개
- 패턴
- Build
- 서귀포
- Linux
- 블루버블
- C
- 현포다이브
- 서귀포블루버블
- C#.NET
- 스쿠버다이빙
- 제주도
- ip
- C#
- 블루버블다이브팀
- CMake
- 블루버블다이빙팀
- 성산블루버블
- 울릉도
- OpenSource
- 스쿠버 다이빙
- Windows
- 윈도우
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
글 보관함
250x250