Old February 25th, 2004, 11:40 AM
Member
 
Join Date: Oct 2003
Posts: 204
urika is an unknown quantity at this point (<10)
putting values in void *arglist

hi ,
i want to run a threads using _beginthread(...)
(no MFC)
inside the threadfunc i want to call a function with many variables.
how do i use the void *arglist so it points to a few variables ?
i hope my question makes sence 
thank u
Reply With Quote
  #2    
Old February 25th, 2004, 11:47 AM
gstercken's Avatar
Moderator
Power Poster
 
Join Date: Sep 2002
Location: 14° 39'19.65"N / 121° 1'44.34"E
Posts: 9,815
gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)
Re: putting values in void *arglist

Quote:
Originally posted by urika 
how do i use the void *arglist so it points to a few variables ?
Usually by creating a class or struct which contains the variables.
You would then use the void* to pass the pointer to an instance of
that class or struct, which you would have to cast back to the actual
type before accessing the members.
__________________
Guido Stercken-Sorrenti
Reply With Quote
  #3    
Old February 25th, 2004, 11:51 AM
Member
 
Join Date: Oct 2003
Posts: 204
urika is an unknown quantity at this point (<10)
thanks!
Reply With Quote
  #4    
Old February 29th, 2004, 05:34 AM
Member
 
Join Date: Oct 2003
Posts: 204
urika is an unknown quantity at this point (<10)
i call a function :
Code:
 bool MapViewInit(GEO p1, GEO p2, DISPLAY Disp, CONTROL Ctrl, HINSTANCE hInst)
{
		MapThreadArgList maparglist;  ////?????
		maparglist.Ctrl=Ctrl;
		maparglist.Disp=Disp;
		maparglist.p1=p1;
		maparglist.p2=p2;
		maparglist.hInst=hInst;
		HANDLE handle1 =(HANDLE)_beginthread( MapThreadFunc,0,
(void *)&maparglist); // create thread COUT << "\n >>> MapViewInit Run Successfully <<<\n"; return true; }
in order to run the thread i do :
Code:
void MapThreadFunc( void* args )
{
		GEO p1;
		GEO p2;
		DISPLAY Disp;
		CONTROL Ctrl;
		HINSTANCE hInst;
		MapThreadArgList arglist = *((MapThreadArgList*)args);
		p1=arglist.p1;
		p2=arglist.p2;
		Disp=arglist.Disp;
		Ctrl=arglist.Ctrl;
		hInst=arglist.hInst;
...
...
...
after i cast back to MapThreadArgList the info in arglist.p1 (and the others ) is lost.
what am i doing wrong?
Reply With Quote
  #5    
Old February 29th, 2004, 06:02 AM
gstercken's Avatar
Moderator
Power Poster
 
Join Date: Sep 2002
Location: 14° 39'19.65"N / 121° 1'44.34"E
Posts: 9,815
gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)gstercken has a reputation beyond repute (3000+)
Quote:
Originally posted by urika 
what am i doing wrong?
You are creating maparglist on the stack - it will be destroyed when it gets out of
scope (when you return from MapViewInit()). Allocate it on the heap, or keep it as a
member variable instead.
__________________
Guido Stercken-Sorrenti
Reply With Quote
  #6    
Old February 29th, 2004, 07:55 AM
Member
 
Join Date: Oct 2003
Posts: 204
urika is an unknown quantity at this point (<10)
thanks , it now works
Reply With Quote

결론
구조체를 사용하여 쓰레드에 넘겨줄 인수를 모두 넣는다. (구조체 정의를 전역변수로 해야 함)
구조체의 객체를 만든 다음 객체멤버에 값을 넣어준다.
통째로 객체를 넘겨준다.
스레드에서 구조체의 객체를 만들어 파라메터의 객체를 받는다.
쓰면된다~ 

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

[Mutex Thread 동기화 예제]  (0) 2011.11.30
[Sleep함수]  (0) 2011.11.29
[CreateThread(), _beginthread(), _beginthreadex()의 차이]  (0) 2011.11.22
[select FD_SET FD_Zero FD_Clr FD_IsSet]  (0) 2011.11.22
[_beginthreadex 형변환문제]  (0) 2011.11.22
Posted by cyj4369
,
윈도우즈에서 스레드를 생성하는 API는 CreateThread(), _beginthread(), _beginthreadex() 이렇게 3개의 함수가 존재합니다. 

CreateThread()와 _beginthread(), _beginthreadex()의 차이점은 다음과 같습니다.
  • CreateThread()는 스레드를 생성하는 기능만 담당한다.
  • _beginthread(), _beginthreadex()는 내부적으로 CreateThread() 를 사용하여 스레드를 생성하고 C Runtime library에서 내부적으로 필요로 하는 메모리 영역을 초기화 해주는 역할을 하게 됩니다. 초기화 되는 메모리 영역은 각 스레드 마다 따로 관리되게 됩니다.


그렇다면 _beginthread(), _beginthreadex()의 차이는 무엇일까요? 의외로 이 차이에 대해서 대답을 명쾌하게 해주는 분이 많지가 않습니다. 이제부터 그 차이를 설명해 보도록 하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

함수 원형을 보고 알 수 있는 파라메터에 의한 차이점은 다음과 같습니다.

  • _beginthreadex()는 security를 이용하여 보안 관련 설정을 할 수 있다.
  • _beginthreadex()는 initflag를 이용하여 스레드의 초기 동작을 정의 할 수 있다.
  • _beginthreadex()는 thrdaddr을 이용하여 thread id를 받을 수 있다.
  • _beginthreadex()는 __stdcall 형식의 함수 포인터를 thread 실행 함수로 받는다.
  • _beginthreadex()는 함수 실행 실패시에 0을 리턴한다. (_beginthread는 -1을 리턴한다.)

여기에 더해서 가장 중요하게 기억해야 할 한가지의 차이점이 더 존재합니다. (이 내용이 글을 쓰는 이유이기도 합니다. ^^)
_beginthread()는 스레드가 생성되고 스레드 함수의 실행이 종료 되면 스레드의 정리 작업을 해주게 됩니다. 이러한 형태는 편리한 점이 있지만 단점도 존재하게 되는데 바로 스레드의 실행 완료후에 해당 스레드의 정보를 조회 할 수 있는 방법이 없다는 것입니다. 

예를 들어 스레드의 종료시에 exit 코드가 무엇인지 알기 위해서 GetExitCodeThread()를 사용할 수 있습니다. 이때 첫번째 인자로 스레드의 핸들을 파라메터로 넘겨줘야 되는데 _beginthread()로 생성된 스레드의 핸들은 GetExitCodeThread()를 사용할 수 없습니다. 

1
2
3
4
BOOL WINAPI GetExitCodeThread(
  HANDLE hThread,
  LPDWORD lpExitCode
);

왜 그럴까요? _beginthread()로 생성된 스레드 핸들은 스레드 함수의 실행이 종료될 때 _beginthread() 내부에서 CloseHandle()을 호출하기 때문에 프로그래머가 GetExitCodeThread()를 사용할 수 있는 시점에서는 이미 소멸된 핸들이 되기 때문입니다.

_beginthreadex()는 위와 같은 문제를 해결하기 위해 스레드가 종료될때 내부적으로 CloseHandle()를 호출하지 않고 사용자가 명시적으로 해제하도록 변경되었습니다.

결과적으로 내용을 정리하면 다음과 같습니다.

  • _beginthread()로 생성된 스레드 핸들은 스레드 종료시에 CloseHandle()이 내부적으로 호출되어 신경쓸 필요가 없지만 스레드 함수 완료 후 스레드 핸들을 이용한 어떠한 API 함수도 실행 시킬 수 없습니다.
  • _beginthreadex()로 생성된 스레드 핸들은 스레드가 실행완료된 후 내부적으로 CloseHandle()을 실행시키지 않기 때문에 스레드 핸들을 이용한 API 함수를 실행할 수 있지만 사용자가 명시적으로 CloseHandle()을 호출해 주어야 합니다. 만약 CloseHandle()을 해주지 않으면 핸들이 계속 쌓이게 되는 Resource leak이 생기게 됩니다.
Posted by cyj4369
,

DWORD = unsigned  long

LPVOID = 헝가리안 표기법에 의해 LP라는 것은 long pointer임 LPVOID는 void*를 의미

 

/*
 http://sosal.tistory.com/
 * made by so_Sal
 */



스레드 (혹은 쓰레드, Thread) 에 대해서 잘 모르신다면
링크로~! ^-^ :: LINK_

/*
 * CreateThread()
 * ExitThread()
 * GetExitCodeThread()

 * _beginthreadex()
 *  ResumeThread();
 * _endthreadex()
 *  -------------
 */
Windows에서 쓰레드를 생성하는 가장 기본적인 함수는
CreateThread 입니다.

HANDLE CreateThread(
1.        LPSECURITY_ATTRIBUTES lpThreadAttributes,
2.        SIZE_T dwStackSize,
3.        LPTHREAD_START_ROUTINE lpStartAddress,
4.        LPVOID lpParameter,
5.        DWORD dwCreationFlags,
6.        LPDWORD lpThreadId        );

1. LPSECURITY_ATTRIBUTES lpThreadAttributes,
SECURITY_ATTRIBUTES 구조체는,
생성하는 핸들에 대해 보안속성을 

2. SIZE_T dwStackSize //dw는 DWORD겠죠 ㅎㅎ
쓰래드는 고유의 스택을 가지고 있습니다. 스택 크기를 지정합니다.
0 (또는 NULL) :: Default 값으로 1mb가 적용됩니다.

3. LPTHREAD_START_ROUTINE lpStartAddress

쓰레드가 작동할 함수의 이름을 넣으시면 됩니다.
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)
                  (LPVOID lpThreadParameter);
typedef PTHREAD_START_ROUTINE    LPTHREAD_START_ROUTINE;

함수 예)
DWORD WINAPI ThreadEx(LPVOID lpParameter){
        return 0;
}

4. LPVOID lpParameter
함수의 인자로 넘어가는것과 같습니다.
더블 포인터도 가능합니다.

5. DWORD dwCreationFlags, //Flag 입니다.
CREATE_SUSPEND
    
:: suspend count 1로 설정 ( 스레드 priority control 관련글 참고 링크 :: LINK_ )
     :: suspend count가 0이 되기 전까지는, 스레드는 동작하지 않습니다.
        이 인자를 넣을 시에, 원하는 시기에 스레드를 시작할 수 있습니다.
        DWORD ResumeThread(HANDLE hThread)   ::  Suspend Count 1 감소
        DWORD SuspendThread(HANDLE hThread)   ::  Suspend Count 1 증가

STACK_SIZE_PARAM_IS_A_RESERVATION 


     :: Reserve stack size를 변경하려면 위 플레그를 추가 한 후 
        스레드 생성 함수들의 매개변수 dwStackSize파라미터를 사용한다.

아래는 CreationFlag이지만, 프로세스에서만 쓰인다. 
CREATE_NEW_CONSOLE
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS 

6. LPDWORD lpThreadId
생성시에 이 변수로 쓰레드ID가 전달됩니다.
필요 없다면 NULL.

return :: HANDLE.
CreateThread 함수의 리턴값은, 스레드를 가리키는 핸들

스레드는 독립된 스택을 할당받기 때문에 메모리를 차지하게 됩니다.
메모리가 허용하는 만큼 스레드 생성이 가능합니다.







void
 ExitThread(DWORD dwExitCode)
이 함수는 실행중인 스레드를 종료하고자 할 때 호출하는 함수입니다.
(사실 return과 다를 바 없다.)
return으로 종료되는 스레드나, 이 함수로 종료되는 스레드나
모두 아래에 설명할 GetExitCodeThread 함수로 리턴값 (혹은 ExitCode값)을
반환받을 수 있다.







스레드의 리턴값을 가져오는 함수입니다.
BOOL GetExitCodeThread(
1        HANDLE hThread,
2        LPDWORD lpExitCode );

1. HANDLE :: 정상적인 리턴으로 종료된 스레드를 가리키는 핸들값
2. lpExitCode :: DWORD 자료형 변수의 주소값을 넣어주면
                       스레드의 리턴값 DWORD값을 반환

다중 프로세스의 경우에, GetExitCodeProcess() 함수 또한,
위와 같이 사용할 수 있습니다. (자료형, 매개변수가 같습니다.)





#include<process.h> 헤더파일이 필요합니다.
uintptr_t _beginthreadex(
          void *_Security,
          unsigned int _StackSize,
          unsigned int(*_StartAdrdress)(void *),
          void *_ArgList,
          unsigned int _InitFlag,
          unsigned int *_ThrdAddr    );

매개변수는 CreateThread와 일치합니다.
매개변수들의 자료형을 더욱 범용적으로 쓰기 위해서
자료형의 형태가 수정되었습니다.

CreateThread() 와 위 함수의 가장 큰 차이점은,
독립적인 메모리 블록 할당에 있습니다.
_beginthreadex() 함수 역시 내부적으로 CreateThread()를 호출합니다. 
종료호출로 ExitThread() 대신, 아래 함수로 대신합니다.
(ExitThread() 함수를 쓰는 이유는 독립적인 "메모리 블록 할당" 에 있습니다.)



void _endthreadex(unsigned retval);
ExitThread() 함수와 역시 동일합니다. 하지만,
_endthreadex() 함수를 쓰는 이유는, 
CreateThread()와 _beginthreadex() 함수간의 차이에 있습니다.
_beginthread() 함수에서는 독립적인 메모리 블록 할당을 한다고 하였습니다.
따라서 스레드 종료시에, 할당한 메모리를 반환해야만 합니다.
이 역할을 하는 함수가 _endthreadex() 입니다.
















======================== CreateThread() 사용 함수 예제 ========================


/*
 * CraeteThread()함수를 이용하여 스레드를 생성한 후
 * 각각의 스레드에 매개변수로 1~10을 넘깁니다.
 * 스레드는 매개변수로 받은 숫자 1~10을 전역변수 STotal 변수에 +=으로 더하고,
 * 매개변수값을 리턴합니다.
 * 메인루틴에서는 스레드가 리턴한값을 차례대로 GetExitCodeThread() 함수를 통해
 * 반환하여 모두 더하고, 전역변수와 리턴값의 합을 출력합니다.
 * ExitThread() 함수는 사용하지 않고, return을 이용했습니다. 
 * ExitThread() 함수를 이용해 직접 짜보시면 이해에 더욱 도움이 될 것 같습니다.
 */


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

#define MAX_THREADS (10)

DWORD STotal = 0;
DWORD WINAPI ThreadProc(LPVOID lpParam);
        // 생성될 Thread가 수행할 내용이 담긴 함수

int _tmain(int argc,TCHAR *argv[]){

 DWORD cntOfThread=0;
 DWORD dwThreadID[MAX_THREADS];
 HANDLE hThread[MAX_THREADS];

 DWORD Total =0;
 DWORD Result=0;
 

while(1){
    if(cntOfThread == MAX_THREADS){
      _tprintf( _T("MAXIMUM THREAD NUMBER : %d\n") ,cntOfThread);
       break;
    }
    hThread[cntOfThread] =
     CreateThread(
         NULL,0,ThreadProc,
         (LPVOID)cntOfThread,
         0,
         &dwThreadID[cntOfThread]);
         cntOfThread++;
}  //while문을 이용하여 10개의 스레드 생성

 Sleep(1000);
 // 스레드가 자신의 할일을 모두 수행하고, 리턴값을 남기고 사라짐
 // 리턴값을 이용하여 Total 계산

 for(DWORD i=0; i<cntOfThread; i++){
  GetExitCodeThread(hThread[i],&Result);
  Total += Result;
  CloseHandle(hThread[i]);
 }
 
 _tprintf( _T(" Total :: %d \n"), Total);      //스레드의 리턴값으로 얻은 Total
 _tprintf( _T("STotal :: %d \n"), STotal);   //스레드가 전역변수에 접근하여 계산된 값
 return 0;
}

DWORD WINAPI ThreadProc(LPVOID lpParam){
   STotal += (DWORD)lpParam; // 전역변수도 접근 가능
   return (DWORD)lpParam;      // 리턴값       전달 가능
}





======================== _beginthreadex() 사용 함수 예제 ========================
/*
 * 위 CreateThread() 예제와
 * 같은 일을 수행합니다.
 */



#include<stdio.h>
#include<windows.h>
#include<tchar.h>
#include<process.h> //beginthreadex() 함수 사용시 필요 헤더파일

#define
 MAX_THREADS (10)

DWORD STotal = 0;
unsigned int WINAPI ThreadProc(LPVOID lpParam);
        // 생성될 Thread가 수행할 내용이 담긴 함수.
        // CreateThread와는 다르게 unsigned int 자료형을 사용합니다.

int _tmain(int argc,TCHAR *argv[]){

 DWORD cntOfThread=0;
 DWORD dwThreadID[MAX_THREADS];
 HANDLE hThread[MAX_THREADS];

 DWORD Total =0;
 DWORD Result=0;
 

while(1){
    if(cntOfThread == MAX_THREADS){
      _tprintf( _T("MAXIMUM THREAD NUMBER : %d\n") ,cntOfThread);
       break;
    }
    hThread[cntOfThread] =
     (HANDLE) _beginthreadex(       //HANDLE로의 형변환이 필요합니다.
         NULL,0,ThreadProc,
         (LPVOID)cntOfThread,
         0,
         (unsigned *)&dwThreadID[cntOfThread]); 
         cntOfThread++;
}  //while문을 이용하여 10개의 스레드 생성

 Sleep(1000);
 // 스레드가 자신의 할일을 모두 수행하고, 리턴값을 남기고 사라짐
 // 리턴값을 이용하여 Total 계산

 for(DWORD i=0; i<cntOfThread; i++){
  GetExitCodeThread(hThread[i],&Result);
  Total += Result;
  CloseHandle(hThread[i]);
 }
 
 _tprintf( _T(" Total :: %d \n"), Total);      //스레드의 리턴값으로 얻은 Total
 _tprintf( _T("STotal :: %d \n"), STotal);   //스레드가 전역변수에 접근하여 계산된 값
 return 0;
}

unsigned int WINAPI ThreadProc(LPVOID lpParam){ //unsigned int 자료형
   STotal += (DWORD)lpParam; // 전역변수도 접근 가능
   return (DWORD)lpParam;      // 리턴값       전달 가능
}

Posted by cyj4369
,