336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

※ C++ 소스 코드 상에서 현재 윈도우가 32bit 버전인지 64bit 버전인지 구분하는 방법에 대한 자료는 검색해보면 금방 구할 수 있습니다. 근데 그 중 많은 자료들이 IsWow64Process 함수 하나만 가지고 64bit 여부를 판단하는 잘못된 방법을 사용하고 있더군요. 이 때문에 많은 분들이 헷갈려 하실것 같아 정확한 방법을 간단하게 정리해서 올려봅니다.



현재 실행중인 프로세스 및 윈도우의 비트(32/64bit) 버전 확인

  

프로그램을 구현하다보면 소스 코드 상에서 현재 실행중인 프로세스가 32bit 버전인지 64bit 버전인지, 또는 64bit 윈도우즈에서 동작중인 32bit 버전(WOW64)인지 구분해할 일이 생길 수 있습니다. 또한 현재 설치된 윈도우가 32bit 버전인지 64bit 버전인지 구분해야 하는 경우도 있구요. 이와 같은 기능은 생각보다 간단하게 구현할 수 있으며, 다음과 같이 기능에 따라 세 가지 함수로 나누어 보았습니다.

 

BOOL IsCurrentProcess64bit()
{
#if defined(_WIN64)
    return TRUE;
#else
    return FALSE;
#endif
}

BOOL IsCurrentProcessWow64()
{
    BOOL bIsWow64 = FALSE;
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS)
                                       GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
    if (!fnIsWow64Process)
        return FALSE;

    return fnIsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64;
}

BOOL Is64BitWindows()
{
    if (IsCurrentProcess64bit())
        return TRUE;

    return IsCurrentProcessWow64();
}

 

 

IsCurrentProcess64bit 함수는 현재 프로세스가 32bit 인지 64bit 인지 확인하는 함수입니다. 사실 어플리케이션이 32bit 인지 64bit 인지는 컴파일 타임에 이미 결정되는 것이기 때문에 함수로 만들 필요 없이 #if defined 매크로를 사용하여 처리해도 되지만 가독성을 위해 함수로 만들어 봤네요.

 

IsCurrentProcessWow64 함수는 현재 프로세스가 WOW64 환경에서 동작중인지 확인하는 함수입니다. WOW64란 "Windows on Windows 64-bit" 의 약자로 64bit 윈도우에서 32bit 어플리케이션이 동작하게 해주는 서브 시스템을 환경을 얘기합니다. 즉, 이 함수는 현재 윈도우가 64bit 이고 현재 프로세스가 32bit 일 경우에만 TRUE를 리턴하게 되며 내부적으로는 IsWow64Process API 함수를 이용하여 구현되어 있습니다.

 

Is64BitWindows 함수는 현재 설치된 윈도우가 32bit 인지 64bit 인지 확인하는 함수입니다. 구글링 하다보니 괜찮은 방법으로 구현된 소스가 있어서 비슷하게 적용해보았습니다. 일단 현재 프로세스가 64bit 일 경우에는 설치된 윈도우는 두 말 할 것도 없이 64bit 입니다. 64bit 어플리케이션은 64bit 윈도우에서만 실행되기 때문이죠. 그리고 현재 프로세스가 32bit 일 경우에는 IsCurrentProcessWow64 함수를 호출하여 판단하면 됩니다. 현재 프로세스가 32bit 이고 WOW64 환경에서 동작하고 있다면 현재 설치된 윈도우는 64bit 라는 결론을 얻을 수 있는거죠.



Reference

 

How to detect programmatically whether you are running on 64-bit Windows


출처 : http://devmachine.blog.me/198372301

'Programming > C / C++' 카테고리의 다른 글

C++ 텔레그램 채널  (0) 2020.02.10
int64_t 값 출력하기  (0) 2015.08.15
to read UTF-8 XML using TinyXML  (0) 2015.08.06
Named Pipe Server Using Overlapped I/O and Client  (0) 2015.06.12
Windows Named Pipe 구현 간단 정리  (0) 2015.06.11
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

VisualStudio 2012, .NET Framework 4.5부터 지원하는 대표적인 기능 중 하나가 바로 비동기 프로그래밍 입니다. 여기서는 비동기 프로그래밍이 무엇인지 정리 드리고자 합니다..

비동기가 왜 필요할까?

웹 2.0 시대가 오면서 OpenAPI, 매쉬업을 통한 개발이 각광받게 되었습니다. 즉, 다른 웹사이트의 자원을 요청하고 가공하여 서비스를 제공하는 경우가 많아지게 된 것이죠. 하지만 이러한 외부 서비스 자원은 가장 느리고 불안정한 자원으로써 서비스의 대기시간이 길어지게 하는 원인으로 작용하게 됩니다. 이렇게 늘어난 서비스 대기시간은 필연적으로 병목을 발생시키고 이는 전체적인 Application의 반응성을 떨어뜨리게 됩니다. 급기야 사용자가 늘어날 수록 비용은 급상승하게 되고 경우에 따라서는 서비스 자체를 불가능하게 만들기도 합니다.

이러한 문제는 비동기 프로그래밍을 통해서 해소될 수 있는데, 비동기 프로그래밍을 위해서는 전문적인 지식과 복잡한 설계를 필요로 합니다. 따라서 고객의 만족을 위해 신뢰할 수 있는 소프트웨어 개발에 집중해야 할 개발자는 비동기 처리를 위해 복잡한 로직을 생산하고 많은 시간을 쓰게 됩니다.

따라서 .NET Framework 4.5부터는 이러한 문제를 해소하고자 async와 await를 통한 비동기 프로그래밍을 지원하고 있습니다. async와 await를 바탕으로 기존의 동기방식의 심플한 구조로 작성할 수 있게 지원하며, 기존에 반복적으로 작성하곤 했던 복잡한 기능들은 .NET Framework가 대신해주게 됩니다.

Application 구분비동기 지원
Web accessHttpClient , SyndicationClient
파일 입출력StorageFileStreamWriterStreamReaderXmlReader
이미지 처리MediaCaptureBitmapEncoderBitmapDecoder
WCF 프로그래밍동기, 비동기 처리를 위한 지원

Async와 Await

async와 await는 비동기로 수행될 메서드를 작성하는데 필요한 핵심적인 키워드 입니다. 이를 통해 비동기로 수행될 메서드를 기존의 동기 메서드 처럼 쉽게 직관적으로 작성할 수 있습니다. async, await를 사용한 메서드를 비동기 메서드(Async Method)라고 합니다. 아래는 비동기 메서드에 대한 간단한 예제입니다.

01// 주목해야할 세가지
02//  - 비동기를 수행하는 메서드는 반드시 aync keyword로 수식해야합니다.
03//  - async keyword가 수식된 메서드는 Async Method로써 반환형은 반드시
04//    void, Task, Task<T> 중 하나여야 합니다. 여기에서는 Task<int>를
05//    반환형으로 지정하였는데 이는 비동기 처리 작업 후 반환되는 데이터가 int이기 때문입니다.
06//  - Convention으로써 Method명을 Async로 끝마침으로써 이 메서드가 비동기 메서드라는 것을 명시해주세요.
07async Task<int> AccessTheWebAsync()
08{
09    HttpClient client = new HttpClient();
10 
11    //아래는 HttpClient에 추가된 GetStringAsync라는 비동기 메서드를 통해서
12    //다른 웹사이트의 접근하는 예제입니다. 이 메서드는 Task<T>를 반환하는데
13    //여기서 Task<T>은 비동기 작업을 나타내는 Type으로써 비동기로 진행 중인 작업정보를 제공합니다.
14    //즉, 아래 Task<string>은 string을 반환하는 비동기 작업을 나타냅니다.
15    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
16 
17    //비동기 메서드 내에도 기존의 동기방식의 처리코드를 포함할 수 있습니다.
18    DoIndependentWork();
19 
20    // Task<string> Type으로 지정된 getStringTask 변수 앞에
21    // await를 지정하였습니다. 이는 변수 getStringTask가 가리키는
22    // 비동기 작업이 완료될 때까지AccessTheWebAsync 메서드를 중단시킵니다.
23    //  - 비동기 작업 getStringTask가 완료될 때 까지 기다립니다.
24    //  - 기다리는 동안 현재 쓰레드의 제어는 AccessTheWebAsync를 호출한 부모에게 넘어갑니다.
25    //  - getStringTask이 완료되기 전까지 작업이 재개되지 않습니다.
26    //  - getStringTask의 작업이 완료되면 await 명령은 변수 urlContents에 작업결과를 담고
27    //    중단된 시점부터 다시 작업을 재개시킵니다.
28    string urlContents = await getStringTask;
29 
30    // 이 비동기 메서드가 완료되길 기다렸던 이 메서드의 호출자에게
31    // 결과를 반환합니다.
32    return urlContents.Length;
33}

위 코드를 바탕으로 async method의 핵심을 요약하면 다음과 같습니다.

  • asnyc로 수식된 메서드는 비동기로 수행되는 메서드가 됩니다.
  • Convention에 의해 메서드명의 접미사는 Async가 됩니다.
  • 비동기 메서드는 다음과 같은 반환형 중 하나를 가집니다.
    • Task<T>: 만약 비동기 메서드의 수행 후 반환되는 데이터가 있다면 반환형을 T에 명시해야 합니다.
    • Task: 비동기 메서드 수행 후 반환되는 데이터가 없을 때 사용합니다.
    • void: 비동기 메서드가 이벤트 핸들러로 사용될 때 void로 명시합니다.
  • 비동기 메서드는 적어도 1개 이상의 await를 포함할 수 있습니다. 하지만 반드시 포함해야 하는 것은 아닙니다. await를 만나면 해당 지점에서 작업이 중단되고 제어는 비동기 메서드를 호출한 호출자에게 넘어가게 됩니다. 이와 별개로 비동기 작업은 따로 진행되게 됩니다. 비동기 작업을 끝마치면 중단된 지점으로부터 다시 작업을 재개하게 됩니다.

위의 예제와 같이 작성된 비동기 메서드는 다음과 같은 방법으로 사용될 수 있습니다.

1//Event Handler에서 다음과 같이 처리하실 수 있습니다.
2private async void Button_Click(object obj, EventArgs e)
3{
4    Task<int> accessTheWebTask = AccessTheWebAsync();
5    string result = await accessTheWebTask;
6    tbxAverageAge.Text = result;
7}

예외처리와 반복문 처리

전통적인 비동기 처리방식으로는 예외처리와 루프처리는 매우 까다로운 작업 중 하나였습니다. 하지만 .NET Framework에서는 동기방식으로 처리하는 것과 동일한 방식으로 작성할 수 있으며 나머지 어렵고 복잡한 부분은 컴파일러가 알아서 처리합니다.

01//비동기 방식으로 처리하기 매우 복잡했던 반복제어, 예외처리도
02//.NET Framework에서는 기존 처리방법과 동일하게 작성하시면 됩니다.
03async Task<int> GetAverageAgeAstnc(string[] userNameList)
04{
05   int averageAge = 0;
06   HttpClient client = new HttpClient();
07   string url = "http://example.com/GetAge?userName=";
08   try
09   {
10      foreach(string userName in userNameList)
11      {
12         int age = await client.GetStringAsync(url + userName);
13         averageAge += age;
14      }
15      return averageAge / userNameList.Length;
16   }
17   catch(Exception ex)
18   {
19      return null;
20   }
21}

실행 흐름

비동기 프로그래밍을 하기 위해 가장 중요한 것은 실행 흐름을 정확하게 이해하는 것입니다. 아래는 Windows Application에서 비동기 작업의 흐름에 대한 예제입니다.

  1. 이벤트 StartButton_Click에 의해 비동기 메서드 AccessTheWebAsync()가 호출됩니다.
  2. HttpClient 인스턴스를 생성하고 비동기 메서드 GetStringAsync()를 호출합니다.
  3. GetStringAsync() 메서드 내부적으로 주어진 주소로 요청을 보내고 응답이 올 때까지 기다리게 되며 기다리는 동안 실행 제어를 호출자에게 넘겨주면서, 현재 작업상태를 Task<string> Type으로 반환하게 됩니다. getStrignTask 변수는 진행 중인 비동기 작업에 대한 정보를 나타냅니다.
  4. 비동기 메서드 GetStringAsync() 이후의 작업인 DoIndepentWork()가 실행됩니다.
  5. DoIndependentWork()는 일반 메서드이므로 동기적으로 실행됩니다.
  6. await는 비동기 작업 getStringTask가 완료될 때까지 AccessTheWebAsync()의 실행을 중단시킵니다. 그리고 현재 쓰레드의 제어를 호출자에게 넘겨줍니다. 또한 현재 AccessTheWebAsync의 작업상태를 나타내는 Task<int>를 생성하게 되며 이를 호출자에게 전달해 줍니다. 
    주의: 비동기 작업 getStringTask가 이미 완료되었다면, 여기서 AccessTheWebAsync는 제어를 중단하지 않고 작업을 계속 이어가게 됩니다.
    제어를 넘겨받은 AccessTheWebAsync의 호출자는 비동기 작업이 완료될 때까지 다른 작업을 수행하게 됩니다.
  7. 비동기 작업 getStringTask의 작업이 완료되면 await는 getStringTask로부터 결과값을 가져와 변수 urlContents에 담고, 중단되었던 지점부터 작업을 재개 시킵니다.
  8. 최종 결과가 호출자에게 반환되게 됩니다.

위와 같은 작업 흐름을 명확하게 이해하는 것이 중요하며, 실제로 작성해보시길 권장 드립니다. 이와 관련한 상세한 예제코드와 설명은 다음 링크에서 확인하실 수 있습니다. (http://msdn.microsoft.com/ko-kr/library/hh873191.aspx)

API Async Methods

.NET Framework에서는 대부분의 시나리오에서 빈번하게 발생하는 요구사항을 해결할 수 있도록 비동기 프로그래밍을 위한 다양한 API를 제공하고 있으며 이를 통해서 비동기 처리가 가능합니다.

위 예제에서는 HttpClient의 GetStringAsync가 하나의 예로써 사용되었습니다. 이와 같은 비동기 API들은 Async라는 접미사를 가지고 있으며 반환형이 Task, Task<T>, void 중 하나이며 (awaitable)이라는 표시가 나타납니다. 

따라서 비동기 처리가 필요한 경우 해당 Async 메서드가 있는지 확인하는 것이 필요합니다. 만약 제공하고 있다면 이를 async, await로 수식함으로써 간단하게 비동기 처리로 전환하실 수 있습니다. 예를 들어 파일을 읽을 경우 기존의 동기작업은 다음과 같이 작성될 수 있습니다.

01public void ReadButton_Click(object sender, EventArgs e)
02{
03    string filePath = @"c:\tmp.txt";
04    using (FileStream sourceStream = new FileStream(filePath,
05        FileMode.Open, FileAccess.Read, FileShare.Read,
06        bufferSize: 4096, useAsync: true))
07    {
08        StringBuilder sb = new StringBuilder();
09 
10        byte[] buffer = new byte[0x1000];
11        int numRead;
12        while ((numRead = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
13        {
14            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
15            sb.Append(text);
16        }
17 
18        tbxResult.Text = sb.ToString();
19    }
20}

이를 비동기로 전환하고자 할 경우 해당 ReadAsync 메서드와 async와 await를 통해 손쉽게 비동기로 바꿀 수 있습니다.

01public async void ReadButton_Click(object sender, EventArgs e)
02{
03    string filePath = @"c:\tmp.txt";
04    using (FileStream sourceStream = new FileStream(filePath,
05        FileMode.Open, FileAccess.Read, FileShare.Read,
06        bufferSize: 4096, useAsync: true))
07    {
08        StringBuilder sb = new StringBuilder();
09 
10        byte[] buffer = new byte[0x1000];
11        int numRead;
12        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
13        {
14            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
15            sb.Append(text);
16        }
17 
18        tbxResult.Text = sb.ToString();
19    }
20}

이와 관련한 자세한 정보는 http://msdn.microsoft.com/library/windows/apps/Hh452713%28v=win.10%29.aspx 에서 확인 하실 수 있습니다.

Threads

비동기 메서드에서 await는 작업을 중단하며 현재 쓰레드의 제어를 부모 메서드로 넘기게 됩니다. async, await 키워드는 추가적인 쓰레드를 생성하지 않으며 따라서 비동기 메서드는 자신만의 쓰레드를 가지지 않으므로 멀티쓰레딩에 대한 고려가 불필요합니다. 비동기 메서드는 Synchronization Context에서 동작하며 그 컨텍스트의 자원을 사용합니다.

Task.Run을 통해서 작업을 백그라운드 쓰레드로 옮길 수 있지만, 백그라운 쓰레드는 해당 작업을 즉시 지원하지 않으며 사용가능해질 때 까지 기다립니다.

비동기 프로그래밍을 위해 async, await를 이용하는 것은 BackgroundWorker(현재 처리를 다른 분리된 쓰레드로 실행하는 Class)를 통한 접근보다 훨신 간결하고, 경쟁상태 등 복잡한 쓰레드에 대한 고려를 요구하지 않습니다.

async와 await

  • await는 async 메서드에서만 사용할 수 있습니다. 일반 메서드에서는 await는 단순한 식별자로 사용되게 됩니다.
  • await는 비동기 메서드 내에서 중단점을 지정하게 됩니다. await 키워드는 컴파일러에게 비동기 작업이 끝나기 전에는 현재 지점 이후로 진행할 수 없음을 알리고, 제어를 호출자에게 넘깁니다. await 키워드는 현재 실행을 잠시 보류하는 것이기 때문에, 제어가 호출자에게 넘어갈 때 finally 블럭이 실행되는 등의 경우는 발생하지 않습니다.
  • async 메서드에 await가 반드시 포함되어야 하는 것은 아닙니다. await가 없는 async 메서드는 동기 메서드와 동일하게 처리됩니다. 또한 컴파일러는 이에 대해 Waring을 생성합니다.

async, await에 대한 보다 자세한 정보는 다음 링크를 확인하세요.

반환형과 매개변수

async 메서드는 Task, Task<T>, void를 반환형으로 가질 수 있습니다. Task, Task<T>에는 async 메서드 뿐만 아니라 다른 방법으로도 생성될 수 있으며 모든 생성된 Task, Task<T>는 await가 적용될 수 있습니다.

반환된 Task는 진행 중인 작업을 나타냅니다. Task는 비동기로 진행 중인 작업상태정보, 최종 결과 정보, 실패했을 때 예외정보까지 포함하고 있습니다.

void 반환형은 보통 비동기 메서드가 이벤트 핸들로러 사용될 때 지정됩니다. 왜냐하면 이벤트 핸들러로 사용되는 delegate가 return type을 void로 정의하고 있기 때문입니다. 하지만 Task를 반환하지 않기 때문에 해당 비동기 메서드를 호출한 호출자는 비동기 메서드에서 발생하는 작업경과나 Exception에 대해서 알 수 가 없습니다.

비동기 메서드에는 out, ref와 같은 Call by reference 형태의 매개변수를 지정할 수 없습니다.

Naming Convention

비동기 메서드는 Async를 Convention에 의해 접미사로 가집니다. 하지만 event, base class, interface에는 이러한 Convention이 생략될 수 있습니다. 예를 들어 Button_Click Event를 Button_ClickAsync로 명시할 필요는 없습니다.

Refernece


출처 : http://nsinc.tistory.com/109

https://msdn.microsoft.com/en-us/library/hh191443.aspx

'Programming > C#' 카테고리의 다른 글

다른 컴퓨터 정보 가져오기  (0) 2015.12.21
ref 와 out 차이  (0) 2015.12.02
Aggregate() vs string.Join()  (0) 2015.04.09
C# Using PostMessage  (0) 2015.03.29
Random Class  (0) 2015.02.08
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Windows 에서는 __int64 타입의 변수를 플랫폼(x86/x64)에 관계없이 printf("%I64d", val) 형태로 출력할 수 있다.

Linux 에서는 플랫폼에 영향이 없이 처리할려면 고려할 사항들이 있다.


x86에서는 long long int 가 64비트 정수이다. 그러나 x64로 넘어가면 long int 가 64비트 정수로 사용된다.

이들 문제로 인해서, 많은 혼선이 발생하고 있다.


일단 정수 타입은 다음과 같이 쓰자.

  • int64_t 타입을 쓰는 걸 권장한다. 여기에는 #include <stdint.h> 가 필요하다.
  • printf() 로 출력하려고 할 때, "%lld" (x86 환경), "%ld" (x64 환경) 이지만, 직접 쓰지 않는다.
    빌드 플랫폼이 바뀔 때마다 이 부분에서 경고가 발생한다.
    대신에 PRId64, PRIu64 를 쓰자. 여기에는 #include <inttypes.h> 가 필요하다.

#include <stdio.h> #include <stdint.h> #define __STDC_FORMAT_MACROS #include <inttypes.h> // PRId64, PRIu64 int main(int argc, char* argv[]) { int64_t val = 60000000000LL; uint64_t val2 = 90000000000000LL; printf("val: %"PRId64"\n", val); printf("val2: %"PRIu64"\n", val2); return 0; }


참고:

출처 : http://netmaid.tistory.com/28

Posted by 역시인생한방
,