1. MFC DLL기반으로 새 프로젝트를 생성한다.(DllApp)

DLL형식=MFC 확장 DLL

 

2.DllMain함수 확인

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

 

// dll이 올라갈 때

if (dwReason == DLL_PROCESS_ATTACH) 사용

 

// dll이 내려갈 때

else if (dwReason == DLL_PROCESS_DETACH) 사용

 

3. 함수만들기

BOOL WINAPI GetModulePath(CString& strPath)

{

}

 



__declspec(dllexport)
BOOL WINAPI GetModulePath(CString& strPath) // 전체 파일의 물리적 경로를 읽어오는 함수
{
 TCHAR szBuffer[MAX_PATH];
 ::ZeroMemory(szBuffer, sizeof(szBuffer));
 ::GetModuleFileName(NULL, szBuffer, MAX_PATH);

 for (int i=lstrlen(szBuffer)-1; 1>=0; --i)
 {
  if (szBuffer[i] == '\\')
  {
   int j = lstrlen(szBuffer)-1;
   for (;j>=i;--i)
   {
    szBuffer[j]=NULL;
   }
   if (szBuffer[j] == ':')
   {
    szBuffer[j+1] = '\\';
   }
   strPath = szBuffer;
   return TRUE;
  }
 }
 return FALSE;
}

 

4. 프로젝트 새로 만들기. MFC응용프로그램. 솔루션에 추가. 대화상자 기반(TestApp)

 

5. 버튼추가하여 캡션 수정(Button1->Call GetModule())

:버튼을 클릭하면 GetModule()함수를 호출하도록.

 

6. stdafx.h파일에 선언

__declspec(dllimport!) BOOL WINAPI GetModulePath(CString& strPath);
#pragma comment(lib, "DllApp")

 

7. 버튼의 이벤트 핸들러 추가

void CTestAppDlg::OnBnClickedButton1()
{
 CString strPath = _T("");
 ::GetModulePath(strPath);

}

 

8."TestApp"를 시작프로젝트로 설정해주고, 빌드시 Appdll.lib파일을 찾을 수 없다는 오류가 나면,

DllApp프로젝트의 디버그 폴더에서 해당파일을 찾아 TestApp프로젝트 폴더로 복사하여 다시 빌드한다.

 

 

암시적링크/명시적링크


'PROGRAMMING > MFC(C++)' 카테고리의 다른 글

소켓 프로그래밍 주요함수  (0) 2011.04.27
[0426수업] Windows Service Process  (0) 2011.04.26
[0425수업] ClipBoard  (0) 2011.04.25
[0422수업] IPC통신  (0) 2011.04.22
[0422수업] 중복실행 방지  (0) 2011.04.22
Posted by 마마필로 :

기능생각...기능에 따른 구현함수나 흐름

외부에서 데이터가 들어올때 그 데이터를 담아놓을 공간을 만드는것이 제일먼저.

 

1. 대화상자 기반의 새 프로젝트 생성(Clipboard)

2. 버튼 두 개, 에디트 컨트롤 한 개 추가

   캡션 수정 Button1(Copy to clipboard), Button2(Read from clipboard)

3. 두 개의 버튼 이벤트 핸들러 추가

3.1 에디트컨트롤에 변수 추가(형식: value, 변수이름: m_strText)

3.2 Button1, Button2 코드 작성

 

**

데이터와 핸들을 받아올때는 무조건 예외처리 코드가 있어야 함!!!

 

void CClipboardDlg::OnBnClickedButton2()
{
 if(!::OpenClipboard(m_hWnd))   return;

 HGLOBAL hGlobalMemory;
 hGlobalMemory = ::GetClipboardData(CF_UNICODETEXT);
 ::EmptyClipboard(); // 다시 초기화 시키고 싶을 때 가장 적당한 위치. 바로 해주는게 좋음
 
 if (hGlobalMemory == NULL)
 {
  // ...
  return;
 }
 
 TCHAR* pszBuffer = (TCHAR*)::GlobalLock(hGlobalMemory);
 if(pszBuffer == NULL)
 {
   // ...
  return;
 }

 m_strText.Format(_T("%s"), pszBuffer);
 ::GlobalUnlock(hGlobalMemory);

 // ::EmptyClipboard();
 ::CloseClipboard();
 UpdateData(FALSE);

}

void CClipboardDlg::OnBnClickedButton1()
{
 UpdateData(TRUE);
 
 if (m_strText.GetLength() <= 0)
  return; // 에디트 컨트롤에 글자 있는지 검사. 없으면 굳이 열어서 쓸필요 없음

 HGLOBAL hGlobalMemory;
 TCHAR* pszBuffer=NULL;
 
 if (::OpenClipboard(m_hWnd) == FALSE)
 {
  AfxMessageBox(_T("ERROR : Failed to open clipboard"));
  return;
 }
 


 int nLength = m_strText.GetLength()*sizeof(TCHAR)+1;
 //문자열대신 이미지를 사용할때는 비트맵사이즈를 이용할 수 있다.
 
 // 가상메모리 공간에 nLength 길이만큼 공간을 할당받는다.
 hGlobalMemory = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, nLength);
 if (hGlobalMemory == NULL)
 {
  AfxMessageBox(_T("ERROR : Failed to allocate global memory"));
  return;
 }

 pszBuffer = (TCHAR*)::GlobalLock(hGlobalMemory);
 wsprintf(pszBuffer, _T("%s"), m_strText);
 ::GlobalUnlock(hGlobalMemory);


 ::EmptyClipboard(); //클립보드를 비워준다
 ::SetClipboardData(CF_UNICODETEXT, hGlobalMemory);
 ::CloseClipboard();

 
}


'PROGRAMMING > MFC(C++)' 카테고리의 다른 글

[0426수업] Windows Service Process  (0) 2011.04.26
[0425수업] dll파일 만들기  (0) 2011.04.25
[0422수업] IPC통신  (0) 2011.04.22
[0422수업] 중복실행 방지  (0) 2011.04.22
[0421수업] 소프트웨어 업데이트  (0) 2011.04.21
Posted by 마마필로 :

Double Pointer(중첩 포인터)

 

int **ppA;

더블 포인터가 가리키는 것은 Single Pointer



scope연산자

::

'PROGRAMMING > C' 카테고리의 다른 글

서식 문자(Conversion Specifier)의 종류와 그 의미  (0) 2011.08.04
논리연산과 비트연산  (0) 2011.08.03
[수업후] 포인터, const  (0) 2011.04.21
[수업후] 포인터와 배열  (0) 2011.04.20
[수업후] 포인터  (0) 2011.04.18
Posted by 마마필로 :

IPC통신 프로그램 작성 순서

 

1.공유메모리(반드시 Virtual Memory공간) 할당, 초기화

2. 문자열을 수신하는 이벤트 생성

3. 이벤트(신호)를 감시하는 스레드 생성

4. 수신한 문자열을 화면에 출력(사용자 정의 메시지 이용)

5. 문자열을 전송하는 부분을 뮤텍스 객체로 동기화

전송하는 쪽에서 스레드를 동기화 시켜야 하는 이유(뮤텍스를 이용하는 이유)

-> 전송하는 응용프로그램이 공유메모리를 쓰는 동안은 다른 프로세스가 접근하지 못하도록 막아두는 것

(동기화 되는 타이밍이 맞지 않을 수 있어 크리티컬 섹션보다는 커널 객체인 뮤택스를 사용한다)

 

 

1. 대화상자 기반의 새 프로젝트(SharedMem) 생성

 

2. 화면구성

버튼1, 리스트박스1, 에디트컨트롤1 추가

 

3. SharedMem.h파일에 객체 선언

class CSharedMemApp : public CWinApp
{
public:
 CSharedMemApp();

 HANDLE m_hMap;
 TCHAR* m_pSharedMemory;
 CMutex m_Mutex;

 CEvent m_ExitEvent;
 CEvent m_ReadEvent;

 

4. SharedMem.cpp에 객체 초기화

4.1 세 개의 커널 객체 초기화

CSharedMemApp::CSharedMemApp()
:m_Mutex(FALSE, TEXT("IPC_TEST_MUTEX")),        //뮤텍스객체 초기화, 이름지어줌
m_ExitEvent(FALSE, TRUE),

m_ReadEvent(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"))    //이벤트객체 초기화, 이름지어줌

{

.

.

.

 

4.2 두개의 핸들과 TCHAR* 초기화

CSharedMemApp::CSharedMemApp()
:m_Mutex(FALSE, TEXT("IPC_TEST_MUTEX")),
m_ExitEvent(FALSE, TRUE),
m_ReadEvent(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"))
{
     m_hMap                          =NULL;
     m_pSharedMemory           =NULL;

     // TODO: 여기에 생성 코드를 추가합니다.
     // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

 

5. <공유메모리를 할당하고 초기화 하는 프로그램 작성> ->자체를 함수로 만들어서 불러오도록 할것임 (SharedMem.cpp에)

함수 만들기

BOOL CSharedMemApp::InitSharedMemory(void)

{

}

 

함수 만들고 바로 헤더파일에서 원형 선언해줌. 잊어버리지 않도록.

BOOL InitSharedMemory(void);

 

코드 작성

BOOL CSharedMemApp::InitSharedMemory(void)
{
     m_hMap   =::CreateFileMapping( INVALID_HANDLE_VALUE,
                                                    NULL,
                                                    PAGE_READWRITE,
                                                    0,
                                                    sizeof(TCHAR)*128,
                                                    _T("IPC_TEST_SHARED_MEMORY"));
     if (::GetLastError() != ERROR_ALREADY_EXISTS)
     {
          m_hMap = ::OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE,
             _T("IPC_TEST_SHARED_MEMORY")); //공유메모리에 파일공간을 만들어 줌
     }

 

     if (m_hMap == NULL)
     {
          AfxMessageBox(_T("ERROR : Failed to create(open) file mapping object!")); // 예외처리:공유메모리가 할당되지 않았을경우 에러메시지 출력
          return FALSE;
     }
 
     m_pSharedMemory = (TCHAR*)::MapViewOfFile( m_hMap,
                                                                          FILE_MAP_ALL_ACCESS,
                                                                          0,
                                                                          0,
                                                                          sizeof(TCHAR)*128);
     if (m_pSharedMemory == NULL)
     {
          AfxMessageBox(_T("ERROR : Failed to get shared memory!")); // 예외처리:공유메모리에 문자열이 없다면 파일생성 하지 않음
          return FALSE;
     }

     return TRUE;
}

 

함수 설명

CreateFileMapping()     // 가상메모리 커널모드 공간에 실제 값을 넣을 수 있는 공간을 만들어줌

pSharedMemory           // 문자를 가리킬 수있는 포인터

MapViewOfFile()          // 전체공간(sizeof(TCHAR)*128)안의 값을 전부다 가지고 오도록 함(통째로). 이 때 실제 값을 가져오는것이 아니라 포인터로 가리키도록 함. (들어가 있는 값만을 가지고 오고자 할 때는 for/while문을 사용하여 null문자를 만날때까지 반복해서 문자를 가져오도록 해야한다.)

 

6.

int CSharedMemApp::ExitInstance()
{
     if(m_pSharedMemory != NULL)  ::UnmapViewOfFile(m_pSharedMemory);
     if(m_hMap != NULL)                 ::CloseHandle(m_hMap);

 

     return CWinApp::ExitInstance();
}

 

7.

BOOL CSharedMemApp::InitInstance()
{
     if (!InitSharedMemory()) return FALSE;

.

.

.

 

<문자열을 수신할 수 있도록 이벤트 객체 생성하고 스레드 만들기>

1. App클래스에 스레드 함수 생성(스레드 함수는 되도록 마법사로...)

 

// 문자열 수신을 위한 이벤트 객체의 생성
UINT CSharedMemApp::ThreadReadSharedMemory(LPVOID pParam)
{
     return 0;
}     // 이벤트가 들어오는 것을 기다리는 함수를 작성(리스너)

 

// 문자열 수신을 위한 이벤트 객체의 생성
UINT CSharedMemApp::ThreadReadSharedMemory(LPVOID pParam)
{
     DWORD dwResult = WAIT_OBJECT_0+1;
     HANDLE arhList[2];
     arhList[0] = theApp.m_ExitEvent;
     arhList[1] = theApp.m_ReadEvent;

 

     while(dwResult == WAIT_OBJECT_0+1)
     {
          dwResult = ::WaitForMultipleObjects(2, arhList, FALSE, INFINITE);
          if(dwResult == WAIT_OBJECT_0)
          {break;}
          else if(dwResult == WAIT_OBJECT_0+1)
          {
               theApp.m_pMainWnd->PostMessage(UM_RECV_EVENT);
               ::Sleep(10);
          }
     }
     return 0;
}//ExitEvent가 나오면 빠져나오도록 조건을 준다

 

 

2. User Message작성(UM_RECV_EVENT), stdafx.h파일에

#define UM_RECV_EVENT WM_USER + 100

 

3.

BOOL CSharedMemApp::InitInstance()
{
     if (!InitSharedMemory()) return FALSE;
     AfxBeginThread(CSharedMemApp::ThreadReadSharedMemory, NULL);

.

.

.


 

<수신 받았을 때 화면에 출력. Dlg클래스>

1. Dlg클래스의 헤더파일에  선언

 

public:
 CListBox m_List;
 CString m_csMessage;

 

2. 특정 메시지에 대응하는 이벤트 처리기 직접 만듬(SharedMemDlg.cpp)

RESULT CSharedMemDlg::OnRecvEvent(WPARAM wParam, LPARAM lParam)
{
     m_List.InsertString(0, theApp.m_pSharedMemory);

     return 0;
}

 

3. 메시지 맵에 작성

BEGIN_MESSAGE_MAP(CSharedMemDlg, CDialog)
     ON_WM_SYSCOMMAND()
     ON_WM_PAINT()
     ON_WM_QUERYDRAGICON()
     //}}AFX_MSG_MAP
     ON_BN_CLICKED(IDC_BUTTON1, &CSharedMemDlg::OnBnClickedButton1)
     ON_MESSAGE(UM_RECV_EVENT, &CSharedMemDlg::OnRecvEvent)
END_MESSAGE_MAP()

 

 

헤더파일(SharedMemDlg.h)의 메시지 맵 함수에도 선언

 

     // 생성된 메시지 맵 함수
     virtual BOOL OnInitDialog();
     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     DECLARE_MESSAGE_MAP()
public:
     afx_msg LRESULT OnRecvEvent(WPARAM wParam, LPARAM lParam);
     afx_msg void OnBnClickedButton1(); 
};

 

<버튼 클릭 이벤트 처리기>

void CSharedMemDlg::OnBnClickedButton1()
{
     if(!UpdateData(TRUE) || m_csMessage.GetLength() <= 0)
      return;

 

     if(theApp.m_Mutex.Lock(1000))
     {
          CEvent EventSend(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"));
          wsprintf(theApp.m_pSharedMemory, _T("%s"), m_csMessage);

          

         EventSend.SetEvent();
          ::Sleep(1);
  

         EventSend.ResetEvent();
          theApp.m_Mutex.Unlock();
     }
     else
     {
          AfxMessageBox(_T("ERROR : Lock() Function is return FALSE!!"));
     }
     m_csMessage = _T("");
     UpdateData(FALSE);
}

 

<아래코드 추가>

 

void CSharedMemDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
     DDX_Control(pDX, IDC_LIST1, m_List);
     DDX_Text(pDX, IDC_EDIT1, m_csMessage);
     DDV_MaxChars(pDX, m_csMessage, 64);
}


'PROGRAMMING > MFC(C++)' 카테고리의 다른 글

[0425수업] dll파일 만들기  (0) 2011.04.25
[0425수업] ClipBoard  (0) 2011.04.25
[0422수업] 중복실행 방지  (0) 2011.04.22
[0421수업] 소프트웨어 업데이트  (0) 2011.04.21
[0421수업] 세마포어  (0) 2011.04.21
Posted by 마마필로 :

1. 단일문서 기반의 프로젝트 생성(Duplex)

 

2. Duplex.h파일(어플리케이션 클래스)에 핸들을 받을 수 있는 변수 선언

-중복실행을 방지하기 위한 것이므로, 실행되기 전에 체크하여 실행되는것 자체를 취소시키기 위해 어플리케이션 클래스에 선언함

class CDuplexApp : public CWinApp
{
public:
     CDuplexApp();
     //CEvent m_Event;
     HANDLE m_hDupCheck; // 핸들을 받을 수 있는 변수 선언

 

3. 어플리케이션클래스(Duplex.cpp)의 InitInstance()함수에 중복실행을 방지하기 위한 코드 작성

아무것도 실행할 필요가 없으므로 바로 비교하고 종료될 수 있도록 맨 위쪽에 코드를 작성해 준다.

 

BOOL CDuplexApp::InitInstance()
{
     ::CreateEvent(NULL, FALSE, FALSE, TEXT("DUPCHECK_THISAPP_EVENT"));
     if (::GetLastError()==ERROR_ALREADY_EXISTS)
     {
          AfxMessageBox(_T("ERROR : Application is already running!"));
          return FALSE; // InitInstance함수가 실행되지 않고 빠져나온다. 이 프로그램은 메모리에 올라가지 않는다.
     }

.

.

.

.

.

 


'PROGRAMMING > MFC(C++)' 카테고리의 다른 글

[0425수업] ClipBoard  (0) 2011.04.25
[0422수업] IPC통신  (0) 2011.04.22
[0421수업] 소프트웨어 업데이트  (0) 2011.04.21
[0421수업] 세마포어  (0) 2011.04.21
[0418수업] ThreadCrash(Critical Section, 뮤텍스)  (0) 2011.04.18
Posted by 마마필로 :

포인터로 함수의 파라미터로 전달

 

call by value //변수의 사본이 복사, 원본은 변하지 않는다

call by reference //주소값으로 호출

 

#include <stdio.h>

void swap(int *a, int *b);

 

int main()
{
     int a=10;
     int b=20;

 

     swap(&a, &b);
     printf("%d %d\n", a, b);

     return 0;
}

 

void swap(int *pa, int *pb)
{
     int temp;

 

     temp=*pa;

     *pa=*pb;
     *pb=temp;

}

 

scanf("%c", &a)

'PROGRAMMING > C' 카테고리의 다른 글

논리연산과 비트연산  (0) 2011.08.03
[수업후] Double Pointer, scope연산자  (0) 2011.04.22
[수업후] 포인터와 배열  (0) 2011.04.20
[수업후] 포인터  (0) 2011.04.18
[수업후] 배열  (0) 2011.04.15
Posted by 마마필로 :

2개의 프로젝트를 만들어 소프트웨어 업데이트 하기

 

1. 단일문서 기반의 첫번째 프로젝트(Update) 생성

Update.h파일에 이벤트 선언

class CUpdateApp : public CWinApp
{
public:
     CUpdateApp()

     CEvent m_ExitEvent;
     CEvent m_UpdateEvent;

 

Update.cpp파일에 생성 코드 추가

CUpdateApp::CUpdateApp()
:m_ExitEvent(FALSE, TRUE), m_UpdateEvent(FALSE, TRUE, TEXT("UPDATE_SW_EVENT"))
{

     // TODO: 여기에 생성 코드를 추가합니다.
     // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

 

2. UpdateApp클래스에 함수 추가

UINT CUpdateApp::ThreadUpdate(LPVOID pParam)
{
     return 0;
}

 

 

//소프트웨어 업데이트를 위한 코드 작성: 소프트웨어 업데이트에서 거의 정형화된 코드이므로 숙지. 외워도 좋음

UINT CUpdateApp::ThreadUpdate(LPVOID pParam)
{
     HANDLE arhList[2];
     arhList[0]=(HANDLE)theApp.m_ExitEvent;
     arhList[1]=(HANDLE)theApp.m_UpdateEvent;

 

     DWORD dwResult=::WaitForMultipleObjects(2, arhList, FALSE, INFINITE);
     if (dwResult==WAIT_OBJECT_0+1)
     {
      CWnd* pMain=theApp.m_pMainWnd;
          if (pMain != NULL) // NULL이면 윈도우가 없고, !=NULL 윈도우가 있다는 것
               pMain->PostMessage(WM_CLOSE);
     }
 return 0;
}

3. Update.cpp에 스레드가 시작할 수 있게 해줌

AfxBeginThread(CUpdateApp::ThreadUpdate,NULL); // InitInstance()함수가 시작되면서 스레드가 돌기 시작함

 

4. UpdapteApp클래스에서 ExitInstance()함수 재정의

int CUpdateApp::ExitInstance()
{
     m_ExitEvent.SetEvent();
     ::Sleep(100);

 

     return CWinApp::ExitInstance();
}

 

 


 

 

5. 대화상자 기반의 두번째 프로젝트(SetUpdate) 생성

 

6. 버튼추가, 캡션 수정(Button1 -> Set UpdateEvent)

 

7. 버튼을 더블클릭하여 이벤트 처리기 생성

void CSetUpdateDlg::OnBnClickedButton1()
{
     CEvent SetUpdateEvent(FALSE, TRUE, _T("UPDATE_SW_EVENT")); // 같은 이벤트 이름으로 설정(UPDATE_SW_EVENT)
     SetUpdateEvent.SetEvent();
     ::Sleep(500);
}

 

 

cf.) 두 프로젝트 모두 <afxmt.h> 인클루드 해주어야 함.

 

<실제 소프트웨어 업데이트에서 이용>

예를 들어 익스플로러를 업데이트 할때 이미 실행되어 있는 이전 버전의 익스플로러 여러개를

업데이트 전에 한번에 다 닫아준 후 업데이트를 시작한다.

이 코드를 실행 후 업데이트를 위한 ShellExecute가 실행된다.

 

프로그램의 중복실행 방지


Posted by 마마필로 :

예를 들어 8개의 스레드가 돌고 있는데 모두 같은 리소스를 사용한다고 가정 하면 이 스레드들은 레이싱 컨디션에 들어간다.

 

이 때, 크리티컬 섹션/뮤텍스를 사용하면 7개를 스탑시키고 한개를 리소스에 접근시켜야 함

그러나 세마포어는 2개이상의 스레드를 접근시키고 나머지는 대기할 수 있도록 하는 것이 가능하다.

 

따라서 크리티컬 섹션/뮤텍스는 두 개의 스레드를 교차 실행 시켜야 할 때.

 

1. 프로젝트 생성, 단일문서기반,  (서비스팩이 설치되어 있다면 오피스 2003)

 

2. stdafx.cpp

CString g_arString[10];
CSemaphore g_SP(3,3);

 

stdafx.h에 <afxmt.h>인클루드

 

extern CString g_arString[10];
extern CSemaphore g_SP;

 

3. Semaphore.h파일의 CwinApp클래스에 CEvent 객체 추가

 

class CSemaphoreApp : public CWinApp
{
 public:
     CSemaphoreApp();
     CEvent m_ExitEvent;    // 종료이벤트

 

 

객체 초기화-> 생성자를 부른다.어플리케이션 클래스의 생성자 함수 안에서 초기화

CSemaphoreApp::CSemaphoreApp()
:m_ExitEvent(FALSE, TRUE)
{
     // TODO: 여기에 생성 코드를 추가합니다.
     // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

 

4. SemaphoreApp에 ExitInstance() 함수 재정의

int CSemaphoreApp::ExitInstance()
{
     m_ExitEvent.SetEvent();

     ::Sleep(1000);

 

     return CWinApp::ExitInstance();
}

5. 특정 클래스 안에 멤버함수로 스레드 만들기(지난번에 한것은 전역함수로 스레드를 만듬)

SemaphoreApp클래스 속성에서 함수 추가

반환 형식: UINT

매개 변수 형식: LPVOID

함수 이름: threadSemaphore

액세스: public

매개 변수 이름: pParam 추가

static(정적함수) 생성

주석: App 클래스에 멤버로서 포함되어진 스레드

 

-> 실제 함수 추가시에 직접 코드를 작성하는 것이 더 편할 수 있다.

하지만 마법사를 이용할경우 헤더파일에 선언부를 자동으로 함께 만들어준다는 장점이 있다.

 

UINT CSemaphoreApp::ThreadSemaphore(LPVOID pParam)
{
     CString strTmp = _T("");
     int nIndex = (int)(pParam);

     

     g_arString[nIndex] = _T("");
     while(::WaitForSingleObject(theApp.m_ExitEvent, 10) == WAIT_TIMEOUT)
     {
         g_arString[nIndex].Format(TEXT("%d Thread is waiting!!"), nIndex);

  

         g_SP.Lock();
         g_arString[nIndex].Format(TEXT("##%d Thread is running!!"), nIndex);
         ::Sleep(100);
         g_SP.Unlock();
     }
     return 0;
}

 

6. Semaphore.cpp에

 for(int i=0; i<10; ++i)
 {
      AfxBeginThread(CSemaphoreApp::ThreadSemaphore, (LPVOID)i);
 }

 

7. 화면에 뭔가 보여주기 위한 작업

뷰클래스에 WM_Create메시지 추가, 여기에 타이머 설정

int CSemaphoreView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
     if (CView::OnCreate(lpCreateStruct) == -1)
          return -1;

     

     SetTimer(100, 1000, NULL);
     // TODO:  여기에 특수화된 작성 코드를 추가합니다.

     

     return 0;
}

 


뷰클래스에 WM_Timer메시지 추가

void CSemaphoreView::OnTimer(UINT_PTR nIDEvent)
{
     CClientDC dc(this);
     dc.FillSolidRect(0, 0, 300, 300, RGB(255, 255, 255));
     for (int i=0;i<10;i++)
     {
          if(g_arString[i].GetAt(0) == '#')
               dc.SetTextColor(RGB(192, 0, 0));
          else
               dc.SetTextColor(RGB(192, 192, 192));

  

         dc.TextOut(30, 20 * i + 10, g_arString[i]);
 }

 

 CView::OnTimer(nIDEvent);
}

 

 

OS가(커널) 스레드를 대기시키고 다른 스레드를 실행하는 기준?

UINT CSemaphoreApp::ThreadSemaphore(LPVOID pParam)
{
     CString strTmp = _T("");
     int nIndex = (int)(pParam);

     g_arString[nIndex] = _T("");
 

     while(::WaitForSingleObject(theApp.m_ExitEvent, 10) == WAIT_TIMEOUT)
     {
          g_arString[nIndex].Format(TEXT("%d Thread is waiting!!"), nIndex);

          g_SP.Lock();
          g_arString[nIndex].Format(TEXT("##%d Thread is running!!"), nIndex);
          ::Sleep(100);
          g_SP.Unlock();
     }
     return 0;

}

 

--> 여기서 while문의 이해가 중요

 

/*다음의 의미를 구별*/

이벤트: 키보드/마우스의 움직임과 같은 행위 그 자체. 행위를 나타내는 일종의 신호(데이터)

메시지:

이벤트 처리기:

메시지 처리기(메시지 처리 함수): 이벤트의 신호에 대응해서 큐에 들어온 메시지를 처리하는 함수

<크리티컬섹션/뮤텍스/세마포어>

스레드를 멈추는것이 목적이 아님.

실행되고 있는 스레드끼리 부딪히는것을 막음.


Posted by 마마필로 :

배열이름값을 정수로 출력하면=첫번째 요소의 주소값

포인터로 첫번째 배열을 가리켰을 때와 같은 값이 출력됨

-> 배열과 포인터의 역할이 동일함을 알 수 있다.

 

*ptr =a; 은 *ptr=&a[0]; 과 같은 의미이다.

 

int a[5]={0, 1, 2, 3, 4}

 

for(int i=0;i<sizeof(a)/sizeof(int);i++) // 배열의 길이가 변해도 for문을 수정하지 않아도 되도록 sezeof를 이용하여 조건식을 작성해준다.

{

}

 

arr[i] = *(arr+i)

 

int main(int argc, char *argv[]) // char *argv[] = char **argv

// argc, argv 콘솔에서만 사용됨

// 콘솔 프로그램: 표준 입력(키보드)/출력(모니터) 장치만 사용하여 입력 또는 출력 받는 프로그램

{

}

 

char형 배열 -> 문자열 상수 표현에 사용

 

#include <stdio.h>

int main()
{
     char str[5]="stop"; // 임시객체, 다음문장이 실행되면 메모리에서 사라진다.
     char *str1="start";


     printf("%c\n", str[0]);
     printf("%d\n", sizeof(str));
     printf("%c\n", *str1);

 

     return 0;

}

'PROGRAMMING > C' 카테고리의 다른 글

[수업후] Double Pointer, scope연산자  (0) 2011.04.22
[수업후] 포인터, const  (0) 2011.04.21
[수업후] 포인터  (0) 2011.04.18
[수업후] 배열  (0) 2011.04.15
[수업후] while, for, 상수, 함수  (0) 2011.04.14
Posted by 마마필로 :

[수업후] 포인터

2011. 4. 18. 03:35 from PROGRAMMING/C

포인터변수

 

5개의 메모리영역

스택 | 큐 | 데이터 | 코드 | 힙

중 힙 영역에 들어감

 

포인터 연산자

* : 값(포인터 값 연산자)

& : 주소(포인터 주소 연산자) -> 자기값의 주소

중첩포인터

int a=10;

int* pA = &a;

int* ppA = &pA;

 

a=10

&a=0x1234

 

pA=0x1234

*pA=10

&=0x5678

 

ppA=0x5678

&ppA=0x3690

*ppA=0x3690

**ppA=10

 

포인터의 출력

*사용시: 실제 원하는 값의 형식(%d, %c, %f, %lf)

&: %p(주소값)

 

 

포인터 오류

int *pA;

*pA=10;

 

Heap에 저장되어 있는 값은 pA의 주소값인데 초기화 되어 있지 않기 때문에 쓰레기값이 들어있다.

따라서 Stack에 값 10을 넣기위한 주소가 명확하지 않기 때문에 오류가 발생한다.

 

이런 오류를 예방하기 위해 포인터 선언과 동시에 초기화 시켜주는 것이 좋다.

int a=10;

int *pA = &a;

'PROGRAMMING > C' 카테고리의 다른 글

[수업후] 포인터, const  (0) 2011.04.21
[수업후] 포인터와 배열  (0) 2011.04.20
[수업후] 배열  (0) 2011.04.15
[수업후] while, for, 상수, 함수  (0) 2011.04.14
[기초] 재귀함수  (0) 2011.04.12
Posted by 마마필로 :