'2010/01'에 해당되는 글 22건

  1. 2010.01.28 o/s의 role
  2. 2010.01.25 소켓함수 예제(로그인서버)
  3. 2010.01.25 파일매핑예제
  4. 2010.01.25 WNDCLASS 구조체
  5. 2010.01.25 스레드의 함정
  6. 2010.01.24 스레드
  7. 2010.01.24 This 포인터
  8. 2010.01.24 이벤트
  9. 2010.01.24 세마포어
  10. 2010.01.24 파일매핑 사용순서
1. 스케줄러

2. MMU 메모리 매핑 유닛

3. Interrupt 관리  - 하드웨어 관리

App > Shell > O/S > Kernel

O/S(Kernel) - 컴퓨터 시스템의 핵이다.


4. NetWork

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

WM_USER And WM_APP  (0) 2010.02.02
레지스트리  (0) 2010.02.02
파일매핑예제  (0) 2010.01.25
WNDCLASS 구조체  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
Posted by 아몰라

#pragma comment(lib , "dll.lib")
#include "Packet.h"
#include "Channel.h"
#include <stdio.h>


///////////////////////////////////////////////////////////////
typedef struct MemberInFo
{
 char *Id;
 char *Pass;
 char *Name;
 int Idlen;
 int Passlen;
 int Namelen;
 int C_Port;
 int SmsPort;
 int FilePort;
 LONG C_Ip;
}MemberInFo;

MemberInFo * member = new MemberInFo();

////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////

void Load(); //Log서버 초기화 후 대기
DWORD WINAPI Send(LPVOID temp); //Login 과 Logout에게 DB서버 정보 전송

void LoginReq(Packet * pack, MsgHead msg, SOCKET sock_Log, SOCKET sock_Db);
void LoginPack(SOCKET sock_Db); //로그인 팩
void LoginUnPack(Packet * pack); //로그인 언팩

void LogoutReq(Packet * pack, MsgHead msg, SOCKET sock_Db); 

int SearchAck(SOCKET sock_Log); //DB로부터 값을 받아서 리턴
void SetState();    //아이디가 있을경우 State 서버로 회원포트정보 등 전송
void SendState(Packet *Pack); //State 서버 초기화

///////////////////////////////////////////////////////////////////

 

int main()

 WSADATA wsaData;
 WSAStartup(MAKEWORD(2,2), &wsaData);
 
 
 
 AllocConsole();
 freopen("conout$","wt",stdout);

 while(1)
 {
  Load();
 } 


 WSACleanup();

 
 delete member;

 return 0;
}


void Load()
{
 DWORD ThreadID;
 SOCKET sock_Log = OpenSocket(LOGSV_IP_ADDR, S_LOG);
 SOCKADDR_IN clientaddr={0,};
 int len = sizeof(clientaddr);
 
 
 SOCKET dosock;

 while(1)
 {
  printf("대기중\n");
  dosock = accept(sock_Log,(SOCKADDR *)&clientaddr,&len); 
  CloseHandle(CreateThread(NULL,0,Send,(LPVOID)dosock,0,&ThreadID));

 }
 closesocket(dosock);
 closesocket(sock_Log);

}

 

DWORD WINAPI Send(LPVOID temp)
{
 SOCKET sock_Log = (SOCKET)temp;
 
 MsgHead msg(sock_Log);  // Msgid 와 Bodylen을 가져온다.  4 + 4
 Packet * pack = new Packet(sock_Log, msg.Getblen()); //  Bodylen 만큼 데이터를 가져온다
 printf("%d", msg.GetMsgid());
 int msgid = msg.GetMsgid();
 
 SOCKET sock_Db = OpenSocket(DBM_IP_ADDR, S_DBM,0);  //Db 와의 연결
 

 switch(msgid)
 {
 case LOGIN: LoginReq(pack, msg, sock_Log, sock_Db); break;
 case LOGOUT: LogoutReq(pack, msg, sock_Db); break;
 default: break;
 }

 
 closesocket(sock_Log); 


 return 0 ;
}

 

void LoginReq(Packet * pack, MsgHead msg, SOCKET sock_Log, SOCKET sock_Db)
{
 int Ack;

 LoginUnPack(pack);
 LoginPack(sock_Db);

 
 if((Ack = SearchAck(sock_Db)))
 {
  send(sock_Log, (char*)&Ack, sizeof(int), 0);
  SetState();
  closesocket(sock_Log);
 }
 else
 {
  send(sock_Log, (char*)&Ack, sizeof(int), 0);
  closesocket(sock_Log);
 }
 
 delete pack;
 closesocket(sock_Db);
}


void LoginUnPack(Packet * pack)
{
 pack->UnPack(&member->Idlen, sizeof(member->Idlen));
 member->Id = new char[member->Idlen];
 pack->UnPack(member->Id, member->Idlen);
 pack->UnPack(&member->Passlen, sizeof(member->Passlen));
 member->Pass = new char[member->Passlen];
 pack->UnPack(member->Pass, member->Passlen);
 pack->UnPack(&member->C_Ip, sizeof(member->C_Ip));
 pack->UnPack(&member->C_Port, sizeof(member->C_Port));
 pack->UnPack(&member->SmsPort, sizeof(member->SmsPort));
 pack->UnPack(&member->FilePort, sizeof(member->FilePort));

 printf("ID:%s, Pass:%s, IP:%d, C_Port:%d, SPort:%d, FPort:%d", member->Id, member->Pass, member->C_Ip, member->C_Port, member->SmsPort, member->FilePort);
}


void LoginPack(SOCKET sock_Db)
{
 MsgHead msg2(LOGIN);

 int bodysize = sizeof(member->Idlen) + member->Idlen + sizeof(member->Passlen) + member->Passlen;

 msg2.SetBlen(bodysize);
 
 Packet * pack2 = new Packet();
 
 pack2->Pack(&msg2, sizeof(MsgHead));
 pack2->Pack(&member->Idlen, sizeof(member->Idlen));
 pack2->Pack(member->Id, member->Idlen);
 pack2->Pack(&member->Passlen, sizeof(member->Passlen));
 pack2->Pack(member->Pass, member->Passlen);
 
 pack2->Send(sock_Db);

 delete pack2;
}

 

void LogoutReq(Packet * pack, MsgHead msg, SOCKET sock_Db)
{

 pack->RePack(&msg, sizeof(MsgHead)); 
 
 pack->Send(sock_Db);
 
 SendState(pack);
 
 
 delete pack;
 closesocket(sock_Db);

 
}

 

int SearchAck(SOCKET sock_Log)  //db로부터 받은 True False 반환!
{
 int re;

 recv(sock_Log, (char*)&re, sizeof(int),0);
  
 printf("\n%d", re);
 
 
 return re;
}

 

void SetState()
{
 MsgHead msg(LOGIN);

 int bodysize = sizeof(member->Idlen) + member->Idlen + sizeof(member->C_Ip) + sizeof(member->C_Port) + sizeof(member->SmsPort) + sizeof(member->FilePort);

 msg.SetBlen(bodysize);
  
 Packet * pack = new Packet();
 
 pack->Pack(&msg, sizeof(MsgHead));
 pack->Pack(&member->Idlen, sizeof(member->Idlen));
 pack->Pack(member->Id, member->Idlen);
 pack->Pack(&member->C_Ip , sizeof(member->C_Ip));
 pack->Pack(&member->C_Port, sizeof(member->C_Port));
 pack->Pack(&member->SmsPort, sizeof(member->SmsPort));
 pack->Pack(&member->FilePort, sizeof(member->FilePort));

 printf("SetState : %d, %d\n",member->C_Ip,member->C_Port);

 
 SendState(pack);

 delete pack;
}

void SendState(Packet *Pack)
{
 SOCKET sock_State = OpenSocket(STATESV_IP_ADDR, S_STATE,0);  //스테이트 서버와 연결

 Pack->Send(sock_State);

 closesocket(sock_State);
}

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

EventSelect란?  (0) 2010.02.05
ASyncSelect 예제  (1) 2010.02.04
소켓통신의 라이브러리 사용 선택 시 고려사항  (0) 2010.02.02
소켓통신(함수정리)  (1) 2010.01.18
OSI 모델 And Ip계층  (0) 2010.01.18
Posted by 아몰라

- 파일 오픈                                                                  hF=CreateFile("test.txt")

- 파일 내용을 메모리에 올린다                                        hMapF=CreateFileMapping(hF)

- 메모리에 올려진 첫번째 주소를 얻는다.                          pF=MapViewOfFile(hMapF)

- 첫번째 주소로 메모리 내용을 조작한다.

- 중간중간에 변경된 내용을 강제로 디스크에 쓰게만든다.    FlushViewOfFile(pF)

- 해제.                                                                        UnmapViewOfFile(pF);

- 해제.                                                                        CloseHandle(hMapF);

- 파일 닫기.                                                                 CloseHandle(hF);

<예제>

#include <windows.h>
#include <stdio.h>

 

int main(int argc, char *argv[])
{
 HANDLE hF, hMapF;
 DWORD fSize, i;
 char *pF, *pFtmp;

 

 hF=CreateFile("test.txt",GENERIC_READ|GENERIC_WRITE, 0,
                                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

 

 fSize=GetFileSize(hF,NULL);

 

 hMapF=CreateFileMapping(
                                         hF,                          //file handle
                                         NULL,
                                         PAGE_READWRITE,
                                         0,                           //file size
                                         0,                           //file size
                                         NULL);                    //map name
 if(hMapF==NULL)
 {
  printf("CreateFileMapping() fail");
  CloseHandle(hF);
  return 1;
 }


 pF=MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,0);
 
 pFtmp=pF;

 for(i=0;i<fSize;i++)
 {
  *pFtmp=(*pFtmp+1);
  pFtmp++;
 }

 

 //메모리 내용을 강제로 파일에 쓴다.
 FlushViewOfFile(pF, 0);

 

 UnmapViewOfFile(pF);

 CloseHandle(hMapF);

 CloseHandle(hF);


 return 0;
}





Share Memory를 만드는 프로세스:

CreateFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle


Share Memory를 Open하는 프로세스:

OpenFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle

 

<예제>

<공유메모리를 만들고 공유메모리에 데이터를 써넣는 프로그램>

#include <windows.h>
#include <stdio.h>

#pragma pack(1)

typedef struct tag_SMTEST
{
 char c;
 int  i;
 short s;
} SMTEST;


int main(int argc, char *argv[])
{
 HANDLE hMapF;
 SMTEST *psm;

 

// JJBSMTEST라는 이름으로 공유메모리를 만든다.

 hMapF=CreateFileMapping(
                                         INVALID_HANDLE_VALUE,
                                         NULL,
                                         PAGE_READWRITE,
                                         0,    
                                         sizeof(SMTEST),    
                                         "JJBSMTEST");   
 if(hMapF==NULL)
 {
  printf("CreateFileMapping() fail");
  return 1;
 }
 psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));
//이후부터 psm 포인터만 읽으면 파일의 내용을 자유롭게 액세스할 수 있다. 
// 파일이 프로세스의 주소 공간에 맵되어 있으므로 포인터를사용하면 연결된 파일의 원하는 부분을 읽을 수 있다.

 psm->c='a';
 psm->i=100;
 psm->s=10;

 

//아래 프로그램을 실행할수있게 시간을 주자

 Sleep(10000);
 
 UnmapViewOfFile(psm);

 CloseHandle(hMapF);

 return 0;
}

  

<예제>

<공유메모리에 접근하여 데이터를 출력하는 프로그램.>

#include <windows.h>
#include <stdio.h>

#pragma pack(1)

typedef struct tag_SMTEST
{
 char c;
 int  i;
 short s;
} SMTEST;


int main(int argc, char *argv[])
{
 HANDLE hMapF;
 SMTEST *psm;

// JJBSMTEST라는 이름으로 공유메모리에 접근한다.

 hMapF=OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "JJBSMTEST");
 
 if(hMapF==NULL)
 {
  printf("OpenFileMapping() fail");
  return 1;
 }
 psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));

 

 //공유메모리에 설정된 내용을 출력한다.
 printf("c:%c i:%d, s:%d\n",psm->c,psm->i,psm->s);
 
 UnmapViewOfFile(psm);

 CloseHandle(hMapF);

 return 0;
}

<예제> 파일을 메모리에 올려놓고 마음대로 불러다 쓴다.

typedef struct Member
{
 char Id[256];
 char name[256]; 
}Member;


Member * member;
Member mem[1000];

void Init()
{

 int i=0;
  
 for(i=0; i<1000; i++)
 {
  strcpy(mem[i].Id,   "22");
  strcpy(mem[i].name,   "22");
 }
}


void FileSet()
{
 DWORD dwWritten;
 
 
 hFile = CreateFile("c:\\jinyong.dat", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
 
 if(hFile!=INVALID_HANDLE_VALUE)
 {
  WriteFile(hFile, mem, sizeof(Member)*1000, &dwWritten, 0);
 }
 
 CloseHandle(hFile);
}


void Mapping()
{
 HANDLE hFile2;

 int i=0;
 hFile2 = CreateFile("c:\\jinyong.dat", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
 if(hFile2 != INVALID_HANDLE_VALUE)
 {
  hMap = CreateFileMapping(hFile2, NULL, PAGE_READWRITE, 0, 0, NULL);
  member = (Member *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 }
 printf("%s\n",member[2].Id);
 printf("%s\n",member[3].name);

}
 

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
WNDCLASS 구조체  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
Posted by 아몰라

 typedef struct tagWNDCLASS
{
      UNIT style;
      WNDPROC lpfnWndProc;
      int cbClsExtra;
      int cbWndExtra;
      HINSTANCE hInstace;
      HICON hIcon;
      HCURSOR hCursor;
      HBRUSH hbrBackground;
      LPCSTR lpszMenuName;
      LPCSTR lpszClassName;
}WNDCLASS;

lpszClassName - 등록하고자 하는 윈도우 클래스의 이름을 나타내는 문자열이며 윈도우 클래스의 구분에 사용된다.

hInstace - 윈도우 클래스를 등록한 응용 프로그램의 인스턴스 핸들이다. 이 멤버가 지정한 응용 프로그램이 이 윈도우 클래스의 소유주가 되며 소유주가 파괴되면 윈도우 클래스도 같이 파괴된다. 메인 윈도우를 만들 때는 WinMain으로 전달된 hHinstance 인수를 그대로 대입하면 된다.


lpfnWndProc - 메시지 처리 함수를 지정한다. 이 클래스로부터 만들어진 윈도우에 메시지가 전달되면 이 멤버가 지정하는 함수로 메시지가 전달되어 윈도우 고유의 처리를 하게 된다. 메인 윈도우 하나로 구성된 프로그램이라면 이 멤버의 값은 선택의 여지없이 WndProc이 될 것이나 차일드 윈도우나 팝업 윈도우가 있다면 다른 이름이 될 수도 있다.

hCursor - 클래스 커서를 지정한다. 이 클래스로부터 만들어진 윈도우의 작업영역에 마우스가 위치해 있을 때 이 멤버가 지정하는 커서가 사용된다. 리소스에 커서를 추가하고 LoadCursor 함수로 읽어 커서 핸들을 대입하거나 디폴크 커서 중 하나를 대입한다.

hIcon - 타이틀 바의 좌상단에 보여줄 아이콘과 윈도우가 최소화되었을 때 보여줄 아이콘을 지정한다. NULL일 경우 아이콘을 그려야할 때 운영체제가 WM_ICONERASEBKGND 메시지를 보내는데 이 때 원하는 아이콘을 직접 그려야한다.

hbrBackground - 윈도우의 작업영역을 칠할 배경 브러시를 지정한다. GetStockObject나 그 외 브러시를 만드는 함수를 사용하여 브러시 핸들을 얻은 후 이 멤버에 대입한다.

lpszMenuName -  이 클래스로부터 만들어진 윈도우가 사용할 메뉴를 지정한다.

style - 윈도우 클래스의 스타일을 지정한다. CreateWindow 에서 지정하는 개별 윈도우의 스타일과는 다르지만 결국은 이 클래스로부터 만들어지는 윈도우에 영향을 미친다.

cbClsExtra - 윈도우 클래스에서 사용하고자 하는 여분의 메모리양을 바이트 단위로 지정한다. 운영체제는 윈도우 클래스를 등록할 때 이 멤버가 지정하는만큼의 메모리를 추가로 할당한다.

cbWndExtra - cbClsExtra와 유사하되 개별 윈도우에서 사용하고자 하는 여분의 메모리양을 지정한다. 운영체제는 CreateWindow로 개별 윈도우를 만들 때마다 이 멤버가 지정하는만큼의 메모리를 추가로 할당한다.

출처 - 윈도우즈 API 정복 , 김상형 지음

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

o/s의 role  (0) 2010.01.28
파일매핑예제  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
Posted by 아몰라

주 스레드의 데이터 직접 참조

- 작업 스레드는 주 스레드에 대해 완전히 독립적이어야 하며 주 스레드가 어떤 동작을 하더라도 자신의 작업을 완료할 수 있어야 한다. 그러기 위해서는 작업거리도 자신만의 것을 가져야 하며 주 스레드는 작업 스레드를 위해 사본을 작성하여 전달해야 한다.

예)프린터, 인쇄스레드는 주 스레드가 편집하고 있는 문서가 아닌 별도의 사본을 가져야 하며 사본을 인쇄해야 한다. 주 스레드가 편집하는문서를 바로 인쇄하려고 하면 문서의 뒤쪽은 사용자가 새로 편집한 내용이 될 것이다.


스레드의 실행 순서나 실행 시간에 대해 어떠한 가정도 해서는 안된다.


- 스레드의 작업 시간이 얼마가 걸릴지는 실제로 돌려 보기 전에는 알 수 없다. 마찬가지로 두 스레드가 동시에 실행될 때 어떤 스레드가 먼저 시작하거나 끝날 것이라는 것도 가정해서는 안된다. 스레드는 완전히 독립적인 작업을 해야 하므로 순서가 있는 작업은 스레드로 분리해서는 안되며 만약 정 필요하다면 동기화해야 한다. 스레드의 작업 시간이나 실행, 종료 순서는 확률적으로 계산 할 수 있다하더라도 절대적이지는 않다.


스레드는 항상 재진입 가능하다는 것을 염두에 두어야 한다.

- 스레드가 호출하는 함수에서 이런 실수를 할 가능성이 많은데 스레드가 호출하는 모든 함수들은 항상 재진입 가능성을 염두에 두고 누가 자신을 호출 하더라도 문제 없이 동작하도록 작성해야 한다.

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

파일매핑예제  (0) 2010.01.25
WNDCLASS 구조체  (0) 2010.01.25
스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
Posted by 아몰라
WinMain과 메시지 루프, WndProc, 일반 함수들을 오가며 메시지를 처리하는 일련의 코드들을 스레드 라고한다.

프로세스는 단지 존재하기만 하는 껍데기일 뿐, 실제 작업은 스레드가 담당한다. 프로세스 생성시 하나의 주 스레드가 생성되며 대부분의 경우 주 스레드가 모든 작업을 처리하고 주 스레드가 종료되면 프로세스도 같이 종료된다.
주스레드 = 프로세스


그리고 주스레드 실행도중에 다른 작업을 같이 하고싶으면 스레드를 여러개 더 추가 할 수 있는데 그 스레드들을 실행하는 도중에 주스레드가 종료되면 실행중인 보조 스레드들도 다 종료된다.


스레드생성

HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)


LPSECURITY_ATTRIBUTES lpThreadAttributes - 스레드의 보안 속성을 지정하는데 자식 프로세스로 핸들을 상속하지 않는 한 NULL로 지정하면 된다.

DWORD dwStackSize - 스레드의 스택 크기를 지정하는데 스레드끼리 상호 안정된 동작을 하기 위해 스레드별로 별도의 스택이 할당된다. 스택의 초기 크기를 0으로 지정하면 주 스레드(Create Thread를 호출한 스레드) 와 같은 크기를 가진다. (기본적으로 스레드의 스택은 1M가 예약되며 프로세스의 주소 공간은 2G이므로 생성 가능한 스레드 개수는 약 2000개이다.)

LPTHREAD_START_ROUTINE lpStartAddress -  스레드의 시작 함수를 지정 

스레드 시작함수의 원형 - DWORD WINAPI ThreadFunc(LPVOID lpParameter)

LPVOID lpParameter - 시작 함수로 전달할 작업내용이다. 없을 경우 NULL

DWORD dwCreationFlags - 생성할 스레드의 특성을 지정하는데 0이면 물론 아무 특성 없는 보통 스레드이다. CREATE_SUSPENDED 플래그를 지정하면 스레드를 만들기만 하고 실행은 하지 않는다. 중지된 스레드를 실행 할때는 Resume Thread 함수를 호출한다.

LPDWORD lpThreadId - 스레드를 만든 후 스레드의 ID를 리턴하기위한 출력용 인수로이므로 DWORD형의 변수를 하나 선언한 후 그 변수의 번지를 넘기면 된다. 스레드 ID가 필요한 경우는 별로 없는데 이 경우는 NULL을 전달한다.

CreateThread 함수는 스레드를 만든 후 스레드의 핸들을 리턴하며 에러가 발생했을 경우 NULL을 리턴한다. 리턴된 스레드의 핸들은 이후 이 스레드를 제어하고자 할 때 사용하는데 생성 후 스레드를 더 이상 조작하지 않을 경우 곧바로 핸들을 닫아도 된다. 스레드 핸들과 스레드 자체는 다르므로 핸들을 닫는다고 해서 스레드가 종료되는 것은 아니다. 여섯 번째 인수로 스레드 ID도 리턴 되는데 핸들과 ID의 차이에 대해서 아래에 간략히 적어보겠다.



핸들 - 프로세스 내에서 해당 객체를 액세스할 때 사용하는 한정적인 값이며 이 핸들을 사용하여 객체를 마음대로 조작할 수 있다. (C++의 지역변수)
ID -  시스템 전역적인 값이며 다른 프로세스 ID와 절대 중복되지 않는다. 그래서 프로세스끼리 ID를 전달함으로써 목적이 되는 프로세스 핸들을 다시 오픈할 수 있다. 실행 중인 프로세스의 ID는 작업 관리자에서 쉽게 확인할 수 있다.
(C++에서 Get 함수)

정리 - 프로세스 ID는 프로세스간의 구분을 위한 중복되지 않는 식별값일 뿐이며 ID로부터 직접 프로세스를 제어할 수는 없다. ID로부터 핸들을 발급받아야만 비로소 이 객체를 제어할 수 있다.


스레드종료

자식 쓰레드가 작업을 할 때 주 쓰레드는 자식 쓰레드를 만들기만 하고 종료 상태에는 별로 관심을 두지 않는 것이 보통이다. 특별한 경우를 제외하고 두 쓰레드는 서로 독립적으로 실행될 뿐이다. 그러나 주 쓰레드는 적어도 자식 쓰레드가 종료되었는지의 여부는 주기적으로 조사해 봐야 한다. 이때 사용되는 함수가 GetExitCodeThread 함수이다.

 

BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode);

 

hThread

쓰레드의 핸들 값

lpExitCode

쓰레드의 종료 코드조사를 위한 인수

 

 

때로는 작업 중간에 쓰레드를 종료해야 하는 경우가 있다. 예를 들어 다운로드를 받는 스레드를 만들었는데 중간에 사용자가 다운로드를 취소했다면 더 이상 이 쓰레드는 존재할 필요가 없다. 

쓰레드를 강제 종료할 때 사용되는 함수는 ExitThread 이다.

 

VOID ExitThread (DWORD dwExitCode);

ExitThread 는 쓰레드가 스스로 종료할 때 사용하는데 인수로 종료 코드를 넘겨준다. 쓰레드가 ExitThread 를 호출하면 자신의 스택을 해제하고 연결된 DLL을 모두 분리 후 파괴된다.

TerminateThread는 쓰레드 핸들을 인수로 전달받아 해당 쓰레드를 강제로 종료한다.

 





'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

WNDCLASS 구조체  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Posted by 아몰라

This는 자기 자신을 가르키는 용도로 사용된다. 그래서 자기 참조 포인터라 한다.

class Member 
{

 int Test1;
 int Test2;
public:
 Member(int Test1, int Test2 )
 {
  this->Test1 = Test1;
  this->Test2 = Test2;
 }
 virtual ~Member();
 void View()
 {
  cout<<Test1 <<endl <<Test2<<endl;
 }
 

};
 

int main()
{
 Member M(1, 2);
 M.View();
 return 0;
}


Test1, Test2 은 매개 변수 와 클래스 멤버변수와 이름이 겹친다

하지만 매개변수는 지역변수이므로 그 안에서 멤버변수 Test에는 접근할 수 없다

방법은 this 포인터를 이용해서 해당 객체의 멤버변수를 직접 가르키면 된다


class Member 
{

public:
 
 Member * GetThis()
 {
  return this;
 }
 

};

int main()
{
 Member * p1 = new Member();
 cout<<"포인터 p1 " << p1<<endl;
 cout<<"p1 의 this " << p1->GetThis()<<endl;

 Member * p2 = new Member();
 cout<<"포인터 p2 " << p2<<endl;
 cout<<"p2 의 this " << p2->GetThis()<<endl;

 return 0;
}



'프로그래밍 기초 > C++' 카테고리의 다른 글

반올림함수 만들기  (0) 2010.05.11
가상함수테이블  (0) 2010.03.04
다형성  (0) 2010.03.04
템플릿이란!?  (0) 2009.11.20
Posted by 아몰라


이벤트란 어떤 사건이 일어났음을 알리는 동기화 객체이다?

 

-       크리티컬섹션, 뮤텍스, 세마포어는 주로 공유자원을 보호하기 위해 사용되는 데 비해 이벤트는 그보다는 스레드간의 작업 순서나 시기를 조정하고 신호를 보내기 위해 사용한다.

 

 

이벤트는 윈도우의 메시지와 유사하다?

 

-       사용자가 키보드 누를 때 WM_KETDOWN 메시지를 윈도우 프로시저에게 보내 처리하게 하는 것처럼 정렬이나 다운로드가 끝났을 때 이벤트를 보내 관련된 다른 작업을 하도록 지시할 수 있다.

 

 

자동 리셋 이벤트

대기 상태가 종료되면 자동으로 비신호상태가 된다.

수동 리셋 이벤트

스레드가 비신호상태로 만들 때까지 신호상태를 유지한다.

 

 

이벤트 함수정리

 

이벤트생성함수

 

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL blnitialState, LPCTSTR lpname);

 

lpEventAttributes

보안속성

bManualReset

TRUE이면 수동 리셋 이벤트 FALSE이면 자동 리셋 이벤트

blnitialState

TRUE이면 이벤트를 생성함과 동시에 신호상태로 만든다.

lpname

이름

세마포어와 마찬가지로 첫번째, 네번째인자는 프로세스동기화와 관련있다.

 

 

n  이벤트가 뮤텍스나 크리티컬섹션과 또 다른 점은 대기 함수를 사용하지 않고도 임의적으로 신호상태나 비신호상태를 설정할 수 있다는 점이다. 이때 쓰는 함수가 아래와 같다.

 

신호상태변경함수

 

BOOL SetEvent(HANDLE hEvent)

BOOL ResetEvent(HANDLE hEvent)

 

SetEvent

신호상태로 만든다.

ResetEvent

비신호상태로 만든다.

이런 상태변화가 대기중인 스레드에게는 일종의 신호로 전달된다.

 

 

 

자동 리셋 이벤트

 

       대기 상태를 풀 때 자동으로 이벤트를 비신호상태로 만든다는 뜻이다.

       여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하지않다.

 

 

수동 리셋 이벤트

 

       대기 상태를 풀 때 신호 상태를 그대로 유지하고 ReSerEvent 함수로 일부러 비신호상태로 만들 때만 상태가 변경된다.

        여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하다.



함수 사용 예제

 

HANDLE hEvent;

DWORD WINAPI ThreadSend(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,210,100,"전송완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadSave(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,110,100,"저장완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadCalc(LPVOID temp)

{

             HDC hdc=GetDC(hWndMain);

             for (int i=0;i<10;i++) {

                           TextOut(hdc,10,50,"계산중",6);

                           GdiFlush();

                           Sleep(300);

                           TextOut(hdc,10,50,"기다려",6);

                           GdiFlush();

                           Sleep(300);

             }

             TextOut(hdc,10,50,"계산완료",8);

             ReleaseDC(hWndMain, hdc);

             SetEvent(hEvent);   //신호상태로 바꿔줌

             return 0;

}

 

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

             HDC hdc;

             PAINTSTRUCT ps;

             DWORD ThreadID;

             TCHAR *Mes="마우스 왼쪽 버튼을 누르면 계산을 시작합니다";

 

             switch (iMessage) {

             case WM_CREATE:

                           hWndMain=hWnd;

                           hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  //수동이벤트

                          

                           //hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); // 자동 이벤트

                           return 0;

             case WM_LBUTTONDOWN:

                           InvalidateRect(hWnd,NULL,TRUE);

                           ResetEvent(hEvent);

                           CloseHandle(CreateThread(NULL, 0, ThreadCalc, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSave, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSend, NULL, 0, &ThreadID));

                           return 0;

             case WM_PAINT:

                           hdc=BeginPaint(hWnd, &ps);

                           TextOut(hdc,10,10,Mes,lstrlen(Mes));

                           EndPaint(hWnd, &ps);

                           return 0;

             case WM_DESTROY:

                           CloseHandle(hEvent);

                           PostQuitMessage(0);

                           return 0;

             }

             return(DefWindowProc(hWnd,iMessage,wParam,lParam));

 

WM_CREATE에서 이벤트 객체를 생성하는데 이 때 두 번째 인수로 TRUE를 지정하여 수동 리셋 이벤트가 되도록하였다.

 

가장 위 에 있는 계산스레드가 실행이되는데 계산이 완료되면 SetEvent함수를 호출하여 신호상태로 만든다.

신호상태로 바뀌어지면 대기하고있던 스레드들이 모두 실행 할 수 있다.

 

, 자동리셋은 같은 상황에서 계산스레드가 끝나고 다른 스레드가 실행되는데 그 스레드가 대기함수를 거치면서 신호를 비신호상태로 바꿔놓음으로서 다른 스레드들은 또 대기를 해야한다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
Posted by 아몰라

 

세마포어는 뮤텍스와 유사한 동기화 객체이다?

 

-      뮤텍스는 하나의 공유 자원을 보호하기 위해 사용하지만 세마포어는 제한된 일정 개수를 가지는 자원을 보호하고 관리한다.

 

 

세마포어는 사용가능한 자원의 개수를 카운트하는 동기화 객체이다?

        

-      유효자원이 0이면 즉 하나도 사용 할 수 없으면 세마포어는 비신호상태가 되며 1이상이면, 즉 하나라도 사용할 수 있으면 신호상태가 된다.

 

 

 

신호상태

스레드의 실행을 허가하는 상태이다.

신호상태의 동기화 객체를 가진 스레드는 계속 실행할 수 있다. (신호등의 파란불)

비신호상태

스레드의 실행을 허가하지 않은 상태이다.

신호상태가 될 때까지 스레드는 블록된다. (신호등의 빨간불)



세마포어 개념을 위한 예)

 

-      네트워크를 통해 프로그램을 다운받는 프로그램을 만든다.

 

n  동시에 여러 개의 자료를 다운로드 받는 것이 가능하기는 하지만 별로 효율적이지는 않다.

n  어차피 네트워크의 대역폭은 정해져 있는 것이므로 한꺼번에 다운로드 받는다고 해서 빨라지는 것도 아니고 그렇다고 순서대로 받는 것은 불편하다.

n  동시에 받되 최대 3개까지만 동시 다운로드가 가능하도록 하고싶다.

n  실제 다운로드 툴이나 웹 브라우저도 일정 개수까지만 동시 다운로드를 지원한다.

 

 

 

 

이경우 자원이란 다운로드 권한이라 표현할 수 있을 것이며 세마포어는 이 권한을 카운트 한다. 세마포어의 초기값을 3으로 설정하고 사용자의 요구가 있을 때마다 다운로드 스레드를 생성한다. 스레드에서는 WaitForSingleObject함수를 호출하여 자신이 사용할 수 있는 권한이 아직 남아 있는지 검사해 보고 가능하다면 다운로드 루프로 진입한다. 이때 대기 함수는 세마포어의 카운트를 1감소시켜 자원이 하나 줄어들었음을 기록한다.

 

두번째, 세번째 스레드가 다운로드를 시작하면 세마포어의 카운트는 0이 되며 비신호상태가 된다. 그러면 이후부터 생성되는 스레드는 다운로드 루프로 진입하지 못하고 자원이 사용가능해질 때 까지 대기하게 된다. 대기중에 첫번 째 스레드가 다운로드를 완료하면 세마포어를 풀 것이고 그러면 세마포어는 다시 1증가하여

신호상태가된다.

 

 

 

세마포어 함수정리

 

 

 

세마포어 생성함수

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG llnitialCount, Long lMaximumCount, LPCTSTR lpName);

 

lpSemaphoreAttributes

보안속성

llnitialCount

초기값(최대사용개수에 대한 값)

lMaximumCount

최대사용개수(몇 개의 스레드를 실행시킬수 있나)

lpName

이름

첫번째 , 네번째 인자는 프로세스간의 동기화에 사용된다. 한 프로세스에서만 사용 할 시 NULL 값을 주면된다.

 

 

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

 

hHandle

하나의 동기화 객체가 신호상태가 되기를 기다린다.

dwMilliseconds

타임 아웃 시간

<dwMilliseconds>

1/1000초 단위로 지정하는데 이 시간이 경과하면 설사 동기화 객체가 비신호상태이더라도 즉시 리턴함으로써 무한 대기를 방지한다. 타임 아웃을 INFINITE로 짖어하면 신호상태가 될 때까지 무한정 대기한다.

 

 

 

WaitForSingleObject 리턴값

 

WAIT_OBJECT_0

hHandle 객체가 신호상태가 되었다.

WAIT_TIMEOUT

타임 아웃 시간이 경과하였다..

WAIT_ABANDONED

포기된 뮤텍스

 

 

 

세마포어의 카운트를 증가시켜주는 함수

 

BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

 

hSemaphore

자원을 반환할  세마포어

lReleaseCount

자신이 사용한 자원의 개수를 알려준다.

lpPreviousCount

이전 카운트를 리턴받기 위한 참조 인수

세번째 인자는 이 값에 관심이 없으면 NULL을 넘기면 된다.

 

함수 사용 예제

프로시저실행시

HANDLE hSem;

hsem = CreateSemaphore(NULL, 3, 3 , NULL);

 

마우스왼쪽버튼클릭시

HANDLE hThread;

hThread = CreateThread(NULL, 0, ThreadDownLoad, NULL, 0 , &ThreadID);

 

스레드 진입시

// 다운로드 화면표시 초기화

WaitForSingleObject(hSem, INFINITE);

// 다운로드 실행화면 표시

설명

-      같은 프로세스 내에서 사용할 것이므로 이름을 줄 필요는 없으며 보안 속성도 지정하지 않았다.

-      다운로드 가능 최대 개수는 3으로 설정했으며 처음부터 3개의 자원이 다 사용 가능하므로 초기값도 3이다.

-      왼쪽버튼클릭시 스레드가 생성되고 다운로드 실행화면이 표시된다. 네번째 클릭하게되면  해당 스레드는 WaitForSingleObject에서 대기하다가 어느 스레드가 종료되면 세마포어가 신호상태로되고 기다리던 스레드는 실행하게된다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Posted by 아몰라

 파일매핑 순서

1) CreateFile API로 파일을 연다.

2) CreateFileMapping API로 그 파일에 대한 파일 매핑 객체를 생성한다.

3) MapViewOfFile API로 파일 매핑 객체의 뷰를 생성한다.

 

HANDLE CreateFileMapping(                             //반환값: 객체 핸들 , 실패시 = INVALID_HANDLE_VALUE 반환

      HANDLE hFile,                                           //파일 핸들

      LPSECURITY_ATTIRBUTES lpAttrs,               //보안 속성

      DWORD flProtect,                                        //접근 허가 , 액세스 타입(PAGE_READONLY,

PAGE_READWRITE,PAGE_WRITECOPY)


      DWORD dwMaxSizeHigh,                            //매핑할 크기의 상위 32비트     , 둘다 0이면 전체파일

      DWORD dwMaxSizeLow,                            //매핑할 크기의 하위 32비트     , 둘다 0이면 전체파일

      LPCTSTR lpName);                                    //객체명 , 첫번째 인수를 NULL로 주었을때 다른 프로세스와
                                                                       동기화하기 위한 목적

 

뷰를 만들어 가상 주소 공간에 매핑! >>

매핑해서 파일 읽고 쓰려면 MapViewOfFile API로 '뷰'를 생성해야한다.

뷰는 실제 파일 내용이 매핑되는 가상 주소 영역.

 

LPVOID MapViewOfFile(                      //반환값: 맵핍항 프로그램상의 주소

      HANDLE hFileMapObj,                  //파일 매핑 객체 핸들 ,

      DWORD dwDesiredAccess,         //필요한 접근 제한 액세스 타입(FILE_MAP_WRITE,FILE_MAP_READ,FILE_
                                                     MAP_ALL_ACCESS,FILE_MAP_COPY)

      DWORD dwFileOfsHigh,              //뷰를 실행할 범위의 시작 오프셋 상위 32비트

      DWORD dwFileOfsLow,               //뷰를 실행할 범위의 시작 오프셋 하위 32비트

      SIZE_T dwBytesToMap);             //뷰를 실행할 범위의 크기

  

뷰의 메모리에서 범위를 지정하여 파일 갱신>>

 

BOOL FlushViewOfFile (                                   //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr,                                //갱신할 영역 시작 주소

      DWORD dwNumberOfBytes);                        //갱신할 영역 크기

 

뷰 해제하기 >>

BOOL UnmapViewOfFil(                                    //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr);                               //해체할 뷰의 시작주소

 

파일 매핑 객체 자체가 불 필요하게 될 경우엔 CloseHandle API로 닫기!!

 

 

이름붙은 파일 매핑 객체 핸들을 다른 프로세스에서 가져와 사용하기 >>

HANDLE OpenFileMapping(                               //반환값: 객체 핸들

      DWORD dwDesiredAccess,                         //필요한 접근 권한

      BOOL bInheritHandle,                                 //자식 프로세스에 상속할 것인가?

      LPCTSTR lpName);                                    //객체명  

[출처] 파일매핑|작성자 숙녀라면


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Hooking  (0) 2010.01.15
Posted by 아몰라
이전버튼 1 2 3 이전버튼