#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>
#include <process.h>
#include <time.h>

 

#define DATA_SIZE 256

 

#ifdef _UNICODE
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

 

#ifdef _UNICODE
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

 

#ifdef _UNICODE
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif


typedef struct MSG_BLOCK_TAG
{
 CRITICAL_SECTION mGuard;
 DWORD fReady, fStop;
 volatile DWORD nCons, mSequence;
 DWORD nLost;
 time_t mTimestamp;
 DWORD mChecksum;
 DWORD mData[DATA_SIZE];

} MSG_BLOCK;

 

MSG_BLOCK mBlock = {0,0,0,0,0};

 

unsigned int WINAPI Produce (void *);
unsigned int WINAPI Consume(void *);
void MessageFill (MSG_BLOCK *);
void MessageDisplay( MSG_BLOCK *);

 

DWORD _tmain( DWORD argc, LPTSTR argv[] )
{
 DWORD status;
 HANDLE hProduce, hConsume;

 InitializeCriticalSection( &mBlock.mGuard );
 
 hProduce = (HANDLE) _beginthreadex( NULL, 0, Produce, NULL, 0, NULL );
 hConsume = (HANDLE) _beginthreadex( NULL, 0, Consume, NULL, 0, NULL );

 status = WaitForSingleObject( hConsume, INFINITE );
 status = WaitForSingleObject( hProduce, INFINITE );

 DeleteCriticalSection ( &mBlock.mGuard );

 _tprintf(_T("Producer and consumer thread have terminated \n"));
 _tprintf(_T("Message produced : %d, Consumed : %d Lost : %d \n"), mBlock.mSequence, mBlock.nCons, mBlock.mSequence - mBlock.nCons );
 
 return 0;

}

 

unsigned int WINAPI Produce (void * arg)
{
 srand ( (unsigned int) time(NULL) );
 
 while( !mBlock.fStop )
 {
  Sleep(rand() / 100 );

  EnterCriticalSection( &mBlock.mGuard );

  __try
  {
   if( !mBlock.fStop )
   {
    mBlock.fReady = 0;
    MessageFill( &mBlock );
    mBlock.fReady = 1;
    InterlockedIncrement( &mBlock.mSequence );
   }
  }
  __finally
  {
   LeaveCriticalSection ( &mBlock.mGuard );
  }

  
 }

 return 0;
}

 

unsigned int WINAPI Consume( void * arg )
{
 CHAR command, extra;

 while( !mBlock.fStop )
 {
  _tprintf(_T("\n ** Enter 'c' for Consume; 's' to Stop : "));
  _tscanf("%c%c", &command, &extra);

  if( command == 's' )
  {
   mBlock.fStop = 1;
  }
  else if( command == 'c' )
  {
   EnterCriticalSection( &mBlock.mGuard );
   
   __try
   {
    if( mBlock.fReady == 0)
    {
     _tprintf(_T("No New Message. Try Again later \n"));
    }
    else
    {
     MessageDisplay(&mBlock );
     mBlock.nLost = mBlock.mSequence - mBlock.nCons + 1;
     mBlock.fReady = 0;
     InterlockedIncrement( &mBlock.nCons );
    }
   }
   __finally
   {
    LeaveCriticalSection( &mBlock.mGuard );
   }
  }
  else
  {
   _tprintf(_T("Illegal Command, Try Again \n"));
  }

 }

 return 0;
}

 

void MessageFill( MSG_BLOCK * msgBlock)
{
 DWORD i;
 msgBlock->mChecksum = 0;

 for( i = 0; i< DATA_SIZE; i++)
 {
  msgBlock->mData[i] = rand();
  msgBlock->mChecksum ^= msgBlock->mData[i];
 }

 msgBlock->mTimestamp = time( NULL );

 return;

}

 

void MessageDisplay( MSG_BLOCK * msgBlock )
{
 DWORD i, tcheck = 0;

 for( i = 0; i < DATA_SIZE; i++)
 {
  tcheck ^= msgBlock->mData[i];
 }

 _tprintf(_T("\n Message number %d generated at : %s \n"), msgBlock->mSequence, _tctime( &( msgBlock->mTimestamp )));
 _tprintf(_T("First and last entries : %x %x \n"), msgBlock->mData[0], msgBlock->mData[DATA_SIZE - 1 ]);

 if( tcheck == msgBlock->mChecksum )
 {
  _tprintf(_T("GOOD -> mChecksum was validated. \n"));
 }
 else
 {
  _tprintf(_T("BAD -> mCheckSum failed. message Corrupted \n"));
 }

 return;

}

  C 라이브러리는 단일 스레드 프로세스를 염두에 두고 작성되었으며 일부 함수들이 중간 결과를 저장하기 위해 전역 저장소를 사용한다. 이런 라이브러리는 스레드에 안전하지 않다. 예를 들어 서로 다른 두 스레드가 전역 저장소를 각자 수정하게 되면 이상한 결과가 나올수 있기 때문이다.
 C 라이브러리 함수들이 스레드에 안전하지 않은 이유를 잘 보여주는 함수로 strtok 가 있다. strtok는 문자열을 토큰단위로 분리하는 함수로 한번 호출 할 때마다 다음 토큰의 위치를 돌려준다. 이를 위해 함수는 일련의 함수 호출들 사이에서 영속적 상태를 유지하는데 그 상태를 함수를 호출하는 스레드가 공유하는 정적 저장소에 저장한다는 것이 문제이다. 
 Microsoft C는 LIBCMT.LIB 라는 스레드에 안전한 C 라이브러리 구현을 통해 이러한 문제를 해결한다. 스레드를 생성하고자 하는 경우 CreateThread 함수 대신 _beginthreadex 함수를 사용할 것을 권장한다. _beginthreadex 함수는 스레드 고유 작업 장소를 생성한다. 스레드 종료 시에는 ExitThread 함수 대신 _endthreadex 함수를 사용한다. 이 함수를 사용하려면 헤더 파일들을 포함하기 전에 반드시 전처리 변수 _MT를 정의해야 한다.
 Visual Studio 경우 다중 스레드에서 C 라이브러리를 제대로 사용하려면 다음과 같은 사항을 지켜야한다.
  1) 프로젝트 속성 -> 구성 속성 -> C/C++ -> 코드 생성 -> 런타임 라이브러리에서 다중 스레드 DLL(/MD) 를 선택한다.
  2) 스레드 생성시 _beginthreadex 함수를 종료시에는 _endthreadex 함수 또는 스레드 루틴 끝에서 return 문으로 실행을 끝나게 한다.

출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 생산자 | 소비자  (0) 2017.12.29
[Tip] 동기화  (0) 2017.12.29
[Tip] 프로세스 관리  (0) 2017.12.29
[Example] 이진 검색 트리를 이용한 파일 정렬  (0) 2017.12.29
[Tip] Heap Memory  (0) 2017.12.29

모든 프로세스는 하나나 그 이상의 스레드들을 가진다. 스레드는 실행의 기본 단위이다. 


Windows 프로세스는 다음과 같은 구성 요소를 가진다.
 1) 하나 이상의 스레드들
 2) 다른 프로세스의 주소 공간과 구별되는 가상 주소 공간
 3) 하나나 그 이상의 코드 구역( Code Segment )들 ( DLL 코드 포함 )
 4) 전역 변수들을 담은 하나나 그 이상의 자료 구역들 ( Data Segment )
 5) 환경 변수 정보 / 프로세스 힙 / 핸들 및 자원 정보
한 프로세스 안의 각 스레드는 코드, 전역변수, 환경 문자열, 자원들을 공유한다.

스레드는 다음과 같은 구성 요소를 가진다.
 1) 프로시저 호출, 인터럽트, 예외 처리부 등을 위한 스택
 2) TLS(Thread Local Storage) 각 스레드 만의 고유한 저장소
 3) 스레드 생성시 지정된 스택에 대한 인수 등
 4) 커널이 관리하는 Context 구조체

 1. 프로세스 생성


  가장 기본적인 Windows 프로세스 관리 함수는 스레드 하나를 가진 프로세스를 생성하는 CreateProcess 함수이다. 함수의 원형은 다음과 같다. 
 

 

 CreateProcess 함수는 HANDLE 값을 반환하지 않고 성공 실패 여부만 반환한다. 생성된 프로세스 관련 정보는 PROCESS_INFORMATION 구조체를 통해 전달 받는다.  

 

 

 

 

 파일 핸들과 마찬가지로 프로세스 핸들이나 스래드 핸들도 더 이상 필요하지 않게 되면 닫아주어야 한다.

2. 상속 가능 핸들
  프로세스를 생성 할때 부모 프로세스의 객체들에 대한 핸들을 통해 자식 프로세스에서도 객체들에 접근하고 싶은 상황이 발생한다. 이런 경우 부모프로세스가 가지고 있는 핸들 정보를 자식 프로세스에게 상속 할수 있다. 핸들 값을 상속 하기 위해서는 SECURITY_ATTRIBUTES 구조체의 보안 서술자 필드를 설정해주어야 한다. 상속된 핸들은 원래의 핸들과 개별적인 복사본이다. 부모와 자식이 같은 파일에 서로 다른 파일 포인터를 이용하여 접근한다. 또한 두 프로세스는 자신의 핸들을 각자 닫을 수 있으며 실제로 각자 닫아야 한다.



 

 

 

 

출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Tip] 동기화  (0) 2017.12.29
[Tip] Thread 사용시 주의 사항  (0) 2017.12.29
[Example] 이진 검색 트리를 이용한 파일 정렬  (0) 2017.12.29
[Tip] Heap Memory  (0) 2017.12.29
[Example] 예외 처리  (0) 2017.12.29
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>
#include <process.h>

#define KEY_SIZE 8

#define EMPTY _T ("")
#define YES _T ("y")
#define NO _T("n")
#define CR 0x0D
#define LF 0x0A
#define TSIZE sizeof (TCHAR)

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

#define GetExceptionCode            _exception_code
#define exception_code              _exception_code
#define GetExceptionInformation     (struct _EXCEPTION_POINTERS *)_exception_info
#define exception_info              (struct _EXCEPTION_POINTERS *)_exception_info
#define AbnormalTermination         _abnormal_termination
#define abnormal_termination        _abnormal_termination

unsigned long __cdecl _exception_code(void);
void *        __cdecl _exception_info(void);
int           __cdecl _abnormal_termination(void);

typedef struct _TREENODE
{
 struct _TREENODE *Left, *Right;
 TCHAR key[KEY_SIZE];
 LPTSTR pData;

} TREENODE, *LPTNODE, **LPPTNODE;

#define NODE_SIZE sizeof( TREENODE )
#define NODE_HEAP_ISIZE 0x8000
#define DATA_HEAP_ISIZE 0x8000
#define MAX_DATA_LEN 0x1000
#define TKEY_SIZE KEY_SIZE * sizeof( TCHAR )
#define STATUS_FILE_ERROR 0xE0000001

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage);
VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode);
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

LPTNODE FillTree( HANDLE, HANDLE, HANDLE);
BOOL Scan( LPTNODE );
int KeyCompare(LPCTSTR, LPCTSTR);
BOOL InsertTree( LPPTNODE, LPTNODE );

int _tmain(int argc, LPTSTR argv[])
{
 HANDLE hIn = INVALID_HANDLE_VALUE, hNode = NULL, hData = NULL;
 LPTNODE pRoot;
 BOOL noPrint;
 CHAR errorMessage[0x100] = {0x0, };
 
 int iFirstFile = Options( argc, argv, _T("n"), &noPrint, NULL);
 int iFile = 0;

 for( iFile = iFirstFile; iFile < argc; iFile ++ )
 {
  __try
  {
   hIn = CreateFile( argv[iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

   if( hIn == INVALID_HANDLE_VALUE )
   {
    RaiseException( STATUS_FILE_ERROR, 0, 0, NULL );
   }

   __try
   {
    hNode = HeapCreate( HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, NODE_HEAP_ISIZE, 0);
    hData = HeapCreate( HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, DATA_HEAP_ISIZE, 0);

    pRoot = FillTree(hIn, hNode, hData);

    _tprintf(_T("Sorted file : %s \n"), argv[iFile]);

    Scan( pRoot );

   }
   __finally
   {
    if( hNode != NULL )
    {
     HeapDestroy( hNode );
    }

    if( hNode != NULL )
    {
     HeapDestroy( hData );
    }

    hNode = NULL;
    hData = NULL;

    if( hIn != INVALID_HANDLE_VALUE )
     CloseHandle(hIn);

    hIn = INVALID_HANDLE_VALUE;
    
   }

  }
  __except( (GetExceptionCode() == STATUS_FILE_ERROR || GetExceptionCode() == STATUS_NO_MEMORY) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
  {
   _stprintf( errorMessage, _T("\n %s %s "), _T("sortBT error onfile : "), argv[iFile]);
   ReportError( errorMessage, 0, TRUE );
  }
 }


 return 0;
}

LPTNODE FillTree (HANDLE hIn, HANDLE hNode, HANDLE hData)
{
 LPTNODE pRoot = NULL, pNode;
 DWORD nRead, i;
 BOOL atCR;
 TCHAR dataHold[MAX_DATA_LEN];
 LPTSTR pString;
     
 while (TRUE) {
  pNode = HeapAlloc (hNode, HEAP_ZERO_MEMORY, NODE_SIZE);
  pNode->pData = NULL;
  (pNode->Left) = pNode->Right = NULL;

  if (!ReadFile (hIn, pNode->key, TKEY_SIZE,
    &nRead, NULL) || nRead != TKEY_SIZE)
  
   return pRoot; 
  atCR = FALSE;   

  for (i = 0; i < MAX_DATA_LEN; i++) {
   ReadFile (hIn, &dataHold[i], TSIZE, &nRead, NULL);
   if (atCR && dataHold[i] == LF) break;
   atCR = (dataHold[i] == CR);
  }
  dataHold[i - 1] = _T('\0');


  pString = HeapAlloc (hData, HEAP_ZERO_MEMORY,
    (SIZE_T)(KEY_SIZE + _tcslen (dataHold) + 1) * TSIZE);
  memcpy (pString, pNode->key, TKEY_SIZE);
  pString[KEY_SIZE] = _T('\0');
  _tcscat (pString, dataHold);
  pNode->pData = pString;

  InsertTree (&pRoot, pNode);

 } 
 return NULL;
}

BOOL InsertTree (LPPTNODE ppRoot, LPTNODE pNode)
{
 if (*ppRoot == NULL) {
  *ppRoot = pNode;
  return TRUE;
 }
 if (KeyCompare (pNode->key, (*ppRoot)->key) < 0)
  InsertTree (&((*ppRoot)->Left), pNode);
 else
  InsertTree (&((*ppRoot)->Right), pNode);
 return TRUE;
}

int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
{
 return _tcsncmp (pKey1, pKey2, KEY_SIZE);
}

static BOOL Scan (LPTNODE pNode)
{
 if (pNode == NULL)
  return TRUE;
 Scan (pNode->Left);
 _tprintf (_T ("%s\n"), pNode->pData);
 Scan (pNode->Right);
 return TRUE;
}


DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
 va_list pFlagList;
 LPBOOL pFlag;
 int iFlag = 0, iArg;

 va_start (pFlagList, OptStr);

 while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
    && iFlag < (int)_tcslen (OptStr)) {
  *pFlag = FALSE;
  for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
   *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
     _tcslen (argv [iArg])) != NULL;
  iFlag++;
 }

 va_end (pFlagList);

 for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);

 return iArg;
}

VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode)
{ 
 if (lstrlen (userMessage) > 0)
  ReportError (userMessage, 0, TRUE);

 if (exceptionCode != 0) 
  RaiseException (
   (0x0FFFFFFF & exceptionCode) | 0xE0000000, 0, 0, NULL);
 
 return;
}

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage)
{
 DWORD eMsgLen, errNum = GetLastError ();
 LPTSTR lpvSysMsg;
 _ftprintf (stderr, _T("%s\n"), userMessage);
 if (printErrorMessage) {
  eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, errNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpvSysMsg, 0, NULL);
  if (eMsgLen > 0)
  {
   _ftprintf (stderr, _T("%s\n"), lpvSysMsg);
  }
  else
  {
   _ftprintf (stderr, _T("Last Error Number; %d.\n"), errNum);
  }

  if (lpvSysMsg != NULL) LocalFree (lpvSysMsg); 
 }

 if (exitCode > 0)
  ExitProcess (exitCode);

 return;
}
출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블​

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Tip] Thread 사용시 주의 사항  (0) 2017.12.29
[Tip] 프로세스 관리  (0) 2017.12.29
[Tip] Heap Memory  (0) 2017.12.29
[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>
#include <process.h>

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage);
VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode);

int _tmain(int argc, LPTSTR argv[])
{
 HANDLE hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;
 DWORD nXfer, iFile, j;
 CHAR outFileName[256] = {0x0, }, *pBuffer = NULL;
 OVERLAPPED ov = {0, 0, 0, 0, NULL};
 LARGE_INTEGER fSize;

 for( iFile = 1; iFile < argc; iFile++)
 {
  __try
  {
   if( _tcslen(argv[iFile]) > 250 )
   {
    ReportException(_T("The File name is Too Long"), 1);
   }

   _stprintf(outFileName, "UC_%s", argv[iFile]);

   __try
   {
    hIn = CreateFile(argv[iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

    if( hIn == INVALID_HANDLE_VALUE )
    {
     ReportException(argv[iFile], 1);
    }

    if( !GetFileSizeEx(hIn, &fSize) || fSize.HighPart > 0)
    {
     ReportException(_T("This file is to Large. \n"), 1);
    }

    hOut = CreateFile(outFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);

    if( hOut == INVALID_HANDLE_VALUE )
    {
     ReportException(outFileName, 1);
    }

    pBuffer = ( CHAR * ) malloc(fSize.LowPart);

    if( pBuffer == NULL )
     ReportException(_T("Memory allocation error \n"), 1);

    if( !ReadFile(hIn, pBuffer, fSize.LowPart, &nXfer, NULL ) || (nXfer != fSize.LowPart) )
    {
     ReportException(_T("ReadFile error \n"), 1);
    }

    for(j = 0; j < fSize.LowPart; j++)
    {
     if (isalpha(pBuffer[j]))
      pBuffer[j] = toupper(pBuffer[j]);
    }

    if( !WriteFile(hOut, pBuffer, fSize.LowPart, &nXfer, NULL) || (nXfer != fSize.LowPart))
    {
     ReportException(_T("WriteFile Error \n"), 1);
    }

   }
   __finally
   {
    if( pBuffer != NULL )
    {
     free(pBuffer);
     pBuffer = NULL;
    }

    if( hIn != INVALID_HANDLE_VALUE )
    {
     CloseHandle(hIn);
     hIn = INVALID_HANDLE_VALUE;
    }

    if( hOut != INVALID_HANDLE_VALUE )
    {
     CloseHandle(hOut);
     hOut = INVALID_HANDLE_VALUE;
    }

    _tcscpy(outFileName, _T(""));
   }
  }
  __except (EXCEPTION_EXECUTE_HANDLER)
  {
   _tprintf(_T("Error Processing File %s \n"), argv[iFile]);
   DeleteFile(outFileName);
  }
 }

 return 0;
}

VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode)
{ 
 if (lstrlen (userMessage) > 0)
  ReportError (userMessage, 0, TRUE);

 if (exceptionCode != 0) 
  RaiseException (
   (0x0FFFFFFF & exceptionCode) | 0xE0000000, 0, 0, NULL);
 
 return;
}

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage)
{
 DWORD eMsgLen, errNum = GetLastError ();
 LPTSTR lpvSysMsg;
 _ftprintf (stderr, _T("%s\n"), userMessage);
 if (printErrorMessage) {
  eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, errNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpvSysMsg, 0, NULL);
  if (eMsgLen > 0)
  {
   _ftprintf (stderr, _T("%s\n"), lpvSysMsg);
  }
  else
  {
   _ftprintf (stderr, _T("Last Error Number; %d.\n"), errNum);
  }

  if (lpvSysMsg != NULL) LocalFree (lpvSysMsg); 
 }

 if (exitCode > 0)
  ExitProcess (exitCode);

 return;
}
​출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 이진 검색 트리를 이용한 파일 정렬  (0) 2017.12.29
[Tip] Heap Memory  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29

 Windows 의 구조적 예외 처리( Structured Exception Handling, SEH) 는 주소 접근 위반이나 산술 실패, 시스템 오류 같은 예기치 않은 비 동기적 사건에 대해 응용 프로그램이 대처할 수 있도록 하는 안정적인 메커니즘을 제공한다. 또한 SEH를 이용하면 코드 블록 안의 어느 곳에서도 프로그램을 종류할 수 있으며 그런 종료 상황에서 프로그래머가 지정한 처리 및 오류 복구가 수행되게 할수 있다. 예외 처리 구조가 없다면 NULL 포인터 참조라든가 0으로 나누기 같은 의도치 않은 예외 상황이 발생했을 때 프로그램이 즉시 종료된다. 예외 처리 절차는 다음과 같다.


 1) 예외가 발생한다. 이번 예에서는 0으로 나누기에 의한 예외가 발생했다고 가정한다.

 2) 제어권이 예외 처리부로 넘어간다. GetExceptionCode가 먼저 호출 되고, 반환값이 함수 필터의 인수가 된다.

 3) 필터 함수는 주어진 오류 코드 값에 근거해서 행동을 결정한다.

 4) 이 예에서 예외 코드는 EXCEPTION_INT_DIVIDE_BY_ZERO 이다.

 5) 필터 함수는 예외 처리부를 수행해야 한다고 결정하고, 그에 맞게 EXCEPTION_EXECUTE_HANDLER를 돌려준다.

 6) __except 절에 있는 예외 코드가 수행된다.

 7) 제어권이 __try __except 블록을 벗어난다.


출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Tip] Heap Memory  (0) 2017.12.29
[Example] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29

 여러 개의 프로세스들을 동시에 실행하는 컴퓨터에서는 파일 같은 공유 자원에 대한 접근 중재와 동기화가 중요한 문제가 된다.

Windows 는 파일 전체 또는 일부를 잠글 수 있다. 일단 파일 또는 파일의 일부분을 잠그면 다른 프로세스 또는 같은 프로세스의 다른 스레드는 그 파일 또는 파일의 일부분에 접근 할 수 없다. 잠금은 프로세스 수준에서 강제되는 것이기 때문에 어떠한 프로세스가 기존의 잠금을 위반하면서 파일의 일부에 대해 접근하려 하면 그 접근은 실패한다.

 파일 잠금에서 가장 일반적인 함수는 LockFileEx이다. 확장 I/O 함수군에 속하는 것으로 잠글 64비트 파일 위치와 파일 영역의 범위를 지정하기 위해 중첩 구조체가 필요하다.


 LockFileEx 함수의 원형은 다음과 같다.

 

  BOOL LockFileEx(

HANDLE hFile, // 열린 파일 핸들

DWORD dwFlags, // 잠금 모드와 자물쇠가 풀릴 때까지 기다릴지의 여부를 결정

// LOCKFILE_EXCLUSIVE_LOCK => 읽기/ 쓰기 자물쇠가 된다.

// LOCKFILE_FAIL_IMMEDIATELY => 자물쇠를 얻을 수 없는 경우 즉시 FALSE를 반환한다.

DWORD dwReserved, // 반드시 0으로 설정

DWORD nNumberOfBytesToLockLow, // 잠글 바이트 구간의 길이

DWORD nNumberOfBytesToLockHigh, // 잠글 바이트 구간의 길이

LPOVERLAPPED lpOverlapped);


 UnlockFileEx 함수의 원형은 다음과 같다. dwFlags를 제외한 매개변수는 LockFileEx와 동일하다.


 BOOL UnlockFileEx(

HANDLE hFile, // 열린 파일 핸들

DWORD dwReserved, // 반드시 0으로 설정

DWORD nNumberOfBytesToLockLow, // 잠글 바이트 구간의 길이

DWORD nNumberOfBytesToLockHigh, // 잠글 바이트 구간의 길이

LPOVERLAPPED lpOverlapped);



 파일 잠금을 사용할 때 주의사항이 몇가지 있다.


 1) 자물쇠를 해제할 때에는 파일을 잠갔을 때와 정확히 동일한 구간을 지정해야 한다. 이전의 두 잠금 구간들을 결합해서 한번에 해제한다거나 잠긴 구간의 일부만을 해제하는 것은 불가능 하다.

 2) 새 자물쇠가 기존의 잠긴 영역과 겹쳐서 충돌이 생기면 잠금이 실패한다.

 3) 파일의 끝을 넘는 영역을 잠그는 것이 가능하다.

 4) 자물쇠들이 새로 생성된 프로세스로 상속되지 않는다.


출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

특정 디렉터리 내에 있는 내용을 출력하는 프로그램입니다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>

#define TYPE_FILE 1  
#define TYPE_DIR 2
#define TYPE_DOT 3

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType( LPWIN32_FIND_DATA);
BOOL ProcessItem( LPWIN32_FIND_DATA, DWORD, LPBOOL);
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

int _tmain(int argc, LPTSTR argv[])
{
 BOOL flags[MAX_OPTIONS], ok = TRUE;
 TCHAR pathName[MAX_PATH + 1] , currPath[MAX_PATH + 1], tempPath[MAX_PATH + 1];
 LPTSTR pSlash, pFileName;
 int i, fileIndex;

 fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);

 GetCurrentDirectory(MAX_PATH, currPath);

 if( argc < fileIndex + 1)
 {
  ok = TraverseDirectory(_T("*"), MAX_OPTIONS, flags);
 }
 else 
 {
  for( i = fileIndex; i < argc; i++)
  {
   _tcscpy(pathName, argv[i]);
   _tcscpy(tempPath, argv[i]);
  
   pSlash = _tstrrchr(tempPath, '\\');

   if( pSlash != NULL )
   {
    *pSlash = '\0';
    _tcscat(tempPath, _T("\\"));
    SetCurrentDirectory(tempPath);
    pSlash = _tstrrchr(pathName, '\\');
    pFileName = pSlash + 1;
   }
   else 
   {
    pFileName = pathName;
   }

   ok = TraverseDirectory(pFileName, MAX_OPTIONS, flags) && ok;

   SetCurrentDirectory(currPath);
  }
 }
}

static BOOL TraverseDirectory(LPCTSTR pathName, DWORD numFlags, LPBOOL flags)
{
 HANDLE searchHandle;
 WIN32_FIND_DATA findData;
 BOOL recursive = flags[0];
 DWORD fType, iPass;
 TCHAR currPath[MAX_PATH + 1];

 GetCurrentDirectory(MAX_PATH, currPath);

 for( iPass = 1; iPass <= 2; iPass++)
 {
  searchHandle = FindFirstFile(pathName, &findData);

  do
  {
   fType = FileType(&findData);
   if( iPass == 1 )
   {
    ProcessItem(&findData, MAX_OPTIONS, flags);
   }

   if( fType == TYPE_DIR && iPass == 2 && recursive)
   {
    _tprintf(_T("\n%s\\%s:"), currPath, findData.cFileName);

    SetCurrentDirectory(findData.cFileName);
    TraverseDirectory(_T("*"), numFlags, flags);
    SetCurrentDirectory(_T(".."));
   }
  
  }while( FindNextFile(searchHandle, &findData));

  FindClose(searchHandle);
 }

 return TRUE;

}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
 BOOL isDir;
 DWORD fType;
 fType = TYPE_FILE;
 isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 if (isDir)
  if (lstrcmp(pFileData->cFileName, _T(".")) == 0
    || lstrcmp(pFileData->cFileName, _T("..")) == 0)
   fType = TYPE_DOT;
  else fType = TYPE_DIR;
 return fType;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
 const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
 DWORD fType = FileType(pFileData);
 BOOL longList = flags[1];
 SYSTEMTIME lastWrite;

 if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

 _tprintf(_T("\n"));
 if (longList) {
  _tprintf(_T("%c"), fileTypeChar[fType - 1]);
  _tprintf(_T("%10d"), pFileData->nFileSizeLow);
  FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
  _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
    lastWrite.wMonth, lastWrite.wDay,
    lastWrite.wYear, lastWrite.wHour,
    lastWrite.wMinute, lastWrite.wSecond);
 }
 _tprintf(_T(" %s"), pFileData->cFileName);
 return TRUE;
}

DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
 va_list pFlagList;
 LPBOOL pFlag;
 int iFlag = 0, iArg;

 va_start (pFlagList, OptStr);

 while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
    && iFlag < (int)_tcslen (OptStr)) {
  *pFlag = FALSE;
  for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
   *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
     _tcslen (argv [iArg])) != NULL;
  iFlag++;
 }

 va_end (pFlagList);

 for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);

 return iArg;
}
출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블​

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

1. Windows 환경에서 문자열 처리 방법


  Windows 는 표준 8비트 문자(char / CHAR)와 16비트 문자( C 의 wchar_t )를 지원한다. 8비트 문자는 ASCII 라고 부르며 16비트 문자는 유니코드(Unicode) UTF-16 인코딩을 통해 지원한다.


  UTF-8 : 유니코드를 위한 가변길이 문자 인코딩 방식. 유니코드 한 문자를 표현하기 위해 1바이트에서 4바이트 까지 사용한다.

  UTF-16 : 기본 다국어 평면에 속하는 문자들은 그대로 16비트 값으로 인코딩이 되고 그 이상의 문자는 특별히 정해진 방식으로 32비트 크기로 인코딩 된다.


2. 유니코드와 ASCII 문자열 모드를 선택하여 빌드하기 위한 프로그래밍 방법


 1) 모든 문자와 문자열을 일반적 형식 TCHAR, LPTSTR, LPCTSTR을 이용해서 정의한다.

 2) 유니코드를 사용하고자 하는 경우 모든 소스 모듈에 #define UNICODE와 #define _UNICODE 를 포함시킨다. UNICODE와 _UNICODE 정의에 따라 유니코드와 ASCII 문자열이 결정된다. 이 정의는 반드시 #include <windows.h> 전에 와야 한다.

 3) 바이트 버퍼 길이 들은 sizeof(TCHAR) 를 이용해서 계산한다.

 4) <tchar.h> 에 정의된 범용 C 라이브러리 문자열 및 I/O 함수를 사용한다. _fgettc, _itot 등

 5) 상수 문자열은 다음 세가지 형태 중 하나이어야 한다.

   5.1) "이 문자열은 8비트 문자들을 사용함"

   5.2) L"이 문자열은 16비트 문자들을 사용함"

   5.3) _T("이 문자열은 전처리 구문에 따라 달라짐")

 6) 텍스트 매크로들과 범용 C 라이브러리 함수들의 정의를 위해 windows.h 다음에 tchar.h를 포함한다.


출처 : 위키백과 / Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

+ Recent posts