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
,

select

select 함수는 한개 또는 그 이상의 소켓 상태를 결정하고, 동기 입출력을 수행 하기위해 필요할 경우 대기 하는 함수입니다.

int select (
int
nfds,
fd_set FAR *
readfds,
fd_set FAR *
writefds,
fd_set FAR *
exceptfds,
const struct timeval FAR *
timeout
);

Parameters

nfds
[입력] 버클리 소켓과 호환되는 소켓을 제외 하고는 이 매개변수는 무시됩니다. 버클리 소켓에서 이 매개변수는 I/O 변화를 감지 할 총 소켓의 갯수+1 의 값을 지정하는 용도로 사용합니다.

readfds
[입/출력] 읽기상태의 변화를 감지할 소켓을 지정합니다.

writefds
[입/출력] 쓰기상태의 변화를 감지할 소켓을 지정합니다.

exceptfds
[입/출력] 예외상태 변화를 감지할 소켓을 지정합니다.

timeout
[입력]
select 함수가 기다리기 위한 시간입니다. NULL 일경우 지정한 I/O변화가 발생했을 때까지 계속 기다립니다.

Remarks

select 함수는 한개 또는 그 이상의 소켓상태(I/O의 발생유무 상태)를 결정하는데 사용됩니다. FD_SET 구조체의 타입의 인자인 readfds, writefds, exceptfds는 각각 읽기, 쓰기, 예외상황 발생과 같은 I/O변화가 발생 했을 때 이를 감지할 대상이 되는 소켓들을 지정하는 배열형 구조체 입니다. 즉, 이 세가지 구조체를 통하여 어떤 소켓에서 어떤 I/O 변화 발생을 감지할지를 선택하여 지정할 수 있습니다. FD_SET 구조체를 처리하기 위해서 일련의 매크로들이 제공되게 됩니다. 이러한 매크로들은 버클리 소켓과 호환성이 있습니다. 하지만, 내부적인 표현 방법은 근본적으로 다릅니다.

readfds 매개변수에는 "입력받을 수 있는 상태"(readability)와 같은 입력(Input)에 대해 변화가 발생 했을때 감지할 대상이 되는 소켓들을 지정합니다. 예를들어 소켓이 리슨 상태라면, 상대방의 접속의 요청에 대한 감지나, 수신큐에 데이터가 수신되었을 때 이를 감지 할 수 있게 됩니다. 어플리케이션은 이런 상황이 감지 되었을때 접속을 허용 하거나 데이터를 수신할 수 있습니다.

writefds 매개변수에는 "출력 할 수 있는 상태"(writability)와 같은 출력(Output)에 대해 변화가 발생 했을때 감지할 대상이 되는 소켓들을 지정합니다. 예를들어 소켓이 connect 함수를 처리하고 있으며, 소켓이 성공적으로 접속이 완료되었을때 다른 데이터를 송신 할 수 있다 라는 변화의 감지나, sendto, WSASendTo 등의 함수가 성공적으로 수행 될수 있을때가 언제인지 감지 할 수 있게 됩니다. 어플리케이션은 이런 상황이 감지 되었을때 소켓에 대한 다른 처리를 하거나, 데이터를 송신 할 수 있습니다.

exceptfds 매개변수는 out-of-band 데이터의 감지를 위해서, 또는 예외적인 에러 상황을 감지하기 위해서 사용됩니다.

readfds, writefds, 또는 exceptfds 매개변수중 두개는 NULL을 가질 수 있습니다. 하지만, 적어도 한개는 NULL 이면 않됩니다. 또한 NULL이 아닌 FD_SET 구조체는 적어도 한개의 소켓을 가지고 있어야 한다는 점을 명심하세요.

windsock(2).h 헤더 파일에는 소켓기술자 세트(ex. FD_SET)를 처리하기 위해서 4가지 종류의 매크로를 정의 해 놓고 있습니다. FD_SETSIZE 값은 소켓기술자 세트(ex. FD_SET)에 들어갈 수 있는 소켓 기술자의 최대 갯수를 결정하는 수치입니다. (FD_SETSIZE 의 기본치는 64입니다. 이값은 winsock(2).h 헤더파일에서 FD_SETSIZE 가 정의 되어 있지 않을 경우 FD_SETSIZE를 64로 정의 하므로 이 헤더파일을 인클루드 하기전에 다른 값을 FD_SETSIZE에 정의해서 변경 할 수 있습니다.)
내부적으로, 소켓기술자 세트로 사용되는 FD_SET 구조체 안에 있는 소켓핸들은 버클리 유닉스와 같은 비트 플래그로 표현되지 않습니다(버클리 유닉스 에서는 세트되어 있다는 것을 1로 그렇지 않은 것을 0으로 표현하죠.). 이 소켓핸들 데이터 표현법은 확실히 정의된 것이 아닙니다. 이렇게 확실히 정의 해 놓지 않은 이유는, 다른 소켓환경 사이에서 소프트웨어를 포팅 하려할 때, 많은 확장성을 제공해 주기 위함입니다. FD_SET 구조체를 처리하는 매크로는 다음과 같습니다.

FD_CLR(s, *set)
지정된 소켓 기술자(descriptor)를 세트에서 제거 합니다.

FD_ISSET(s, *set)
지정된 소켓 기술자가 세트에 있을 경우 0이 아닌값을 반환하고, 없을 경우 0을 반환합니다.

FD_SET(s, *set)
지정된 소켓 기술자를 세트에 추가 합니다.

FD_ZERO(*set)
모든 소켓 기술자를 세크에서 제거합니다.


FD_SET

typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;

Element Usage
fd_count 설정하는 소켓의 번호
fd_array 설정된 소켓의 배열


FD_Zero

Clear all file descriptors in set

Declaration

Source position: oldlinux.pp line 1594

procedure FD_Zero(

var fds: fdSet

);

Description

FD_ZERO clears all the filedescriptors in the file descriptor set fds.

For an example, see Select.

Errors

None.


FD_Clr

Clears a filedescriptor in a set

Declaration

Source position: oldlinux.pp line 1595

procedure FD_Clr(

fd: LongInt;

var fds: fdSet

);

Description

FD_Clr clears file descriptor fd in filedescriptor set fds.

For an example, see Select.

Errors

None.




FD_IsSet

Check whether a filedescriptor is set

Declaration

Source position: oldlinux.pp line 1597

function FD_IsSet(

fd: LongInt;

var fds: fdSet

):Boolean;

Description

FD_Set Checks whether file descriptor fd in filedescriptor set fds is set.

For an example, see Select.

Errors

None.

Posted by cyj4369
,
 
2003-01-09 오후 8:18:50   /  번호: 270644   category: VC++ 일반  /  조회: 167
 [급질문]_beginthreadex 에서 BOOL 함수 호출..그리고 파라메터  
리턴 값이 BOOL 인 함수를 쓰레드로 쓸려면 3번째 파라미터에 어떻게 선언해줘야되죠??
그리고 구조체를 파라미터로 넘길려고 그러는데..자꾸 이런에러가 뜨네요.
error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned int (struct st_ComPort *)' to 'unsigned int (__stdcall *)(void *)'
        None of the functions with this name in scope match the target type

어떻게 해야 되죠?? 파라미터를 넘겨야 되죠??
 
  2004-10-15 오전 1:15:26   /  번호: 474101  /  
 Re: _beginthreadex 형변환문제 답변.   
  

 c++ 은 자료형을 엄격히 구분해서 발생하는 문제입니다.


(HANDLE)_beginthreadex(NULL, 0, ClientConn, (void*)clntSock, 0, (unsigned *)&dwThreadID);


요렇게 사용하면 당근 님이 묻는 Error가 발생합니다.


이것땜시 저도 아주 두시간을 헤맸어용...ㅜㅜ;


문제는 세번째 인자에 있습니다. 요걸 이렇게 바꾸면 형변환 문제 해결... 아래 에러 왕짜증..

error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned long (void *)' to 'unsigned int (__stdcall *)(void *)'

        None of the functions with this name in scope match the target type


음 그니까 (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall*)(void*))ClientConn, (void*)clntSock, 0, (unsigned *)&dwThreadID);


위에걸 이렇게 바꿔주시면 해결 될거에요....^^


즐공하세용!!


출처 : 데브피아(http://www.devpia.com)

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
,

setsockopt(IN SOCKET socket, IN int name, IN int optlevel, IN const char* optvalue, IN int optlen);

[1] 입출력 버퍼크기의 변경

SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
int send_buf = 500;
i
nt rcv_buf = 1000;
int state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf));
if(state) errorhandling("setsockopt() error");
state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&send_buf, sizeof(send_buf));
if(state) errorhandling("setsockopt() error");
 

[2] Nagle 알고리즘의 적용 - 한번에 모아서 전송
TCP 소켓은 기본적으로 Nagle 알고림을 사용하여 한번에 모아서 전송함. 지연 발생(100~200ms).
이 옵션 사용시 리턴과 동시에 데이터 전송이 이루어지나 회선 부하가 많아짐.

int sock;
int flag = 1; // 네이글 알고리즘 off
sock = open(...);
if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0)
{
printf("setsockopt error\n");
....
}


[3] 송/수신 TIMEOUT 설정 - 블러킹 소켓일 경우

SCOKET hSocket;
int nErrorCode;
hSocket = socket(AF_INET,SOCK_STREAM,0);
~~~~
nErrorCode = connect(~~~~~~);
~~~
// RECEIVE & SEND TIMEOUT 설정법
// hSocket이 블럭킹상태(Blocking) 일경우 해당된다. 논 블럭킹 상태(None-Blocking) 이면 recv에서 SOCKET_ERROR를 반환하고
//WSAGetLastError()로 확인 하면 WSAEWOULDBLOCK를 반환 한다. 
//WSAEWOULDBLOCK이 에러가 아니고, 다른 에러 이면 에러 코드를 참조 하여 에러 처리를 한다. 
// Receive Time Out Value : 3000 (약 3초)

int nTimeOutValue = 3000;
nErrorCode = setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*) & nTimeOutValue, sizeof(nTimeOutValue));
if(SOCKET_ERROR == nErrorCode){ // 에러 처리
}
nErrorCode = setsockopt(hSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*) & nTimeOutValue, sizeof(nTimeOutValue));
if(SOCKET_ERROR == nErrorCode) { // 에러 처리
}
nErrorCode = send(hSocket,버퍼,전송할 버퍼크기, 0);
~~~
nErrorCode = recv(hSocket,버퍼, 버퍼크기, 0);
~~~

 

[4] 소켓 종료시 종료방식 설정

LINGER 구조체의 _onoff _linger 두개의 값에 플래그를 지정하고 setsockopt 에 설정
l_onoff = 0, l_linger = 0(또는 1) : 버퍼에 있는 내용을 모두 전송후 연결 종료한다.
l_onoff = 1, l_linger = 0 : 즉시 연결을 종료한다. 상대방에게는 FIN이나 RTS 시그널이 전달된다.
l_linger = 1 : 버퍼에 있는 내용을 모두 전송후에 연결을 종료한다. 이 동안 closesocket 은 block 된다.

LINGER opt = {onoff, linger}; // 값을 설정
setsockopt(socket, SOL_SOCKET, SO_LINGER, (char *)&opt, sizeof(opt));


[5] 소켓 비정상 종료시 재 bind 를 허용하도록 함

bind 되었던 소켓이 서버의 비정상 종료로 커널이 아직 그 정보를 갖고 있을 경우, 다시금 bind 할 수 없는 경우가 있는데, 이때 선점된 주소로 인해 bind에 실패할 수 있다. 이 옵션은 재 bind 할 수 있도록 한다.

bool reuseflag = true;
setsockop(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseflag, sizeof(reuseflag));
 

[6] UDP 소켓을 브로드캐스트 가능하도록 설정

디폴트로 생성되는 UDP소켓은 브로드캐스트가 불가능하도록 설정되어있다. 이 소켓을 브로트캐스트가 가능하도록 한다.
 

// serverside
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(szServerAddress);
serverAddr.sin_port = htons(nPort); // 포트는 serverside 와 clientside 모두 통일
state = setsockopt(hSock, SOL_SOCKET, SO_BROADCAST, (char *)&serverAddr, sizeof(serverAddr)); 

Posted by cyj4369
,

파일 입 출력

 

#include <stdio.h>

 

FILE* fopen(const char * filename, const char *mode)

 

 filename

개방하고자 하는 파일의 경로명과 파일명을 동시에 지니는 문자열

 ) filename = “c:\\work\\test.dat” (c:\\work 는 경로명 test.dat 은 파일명)

   *특수문자 역슬래시(\)와 구분하기 위해 (\\) 를 두개 써준다.

 mode

파일의 특징 및 용도를 결정짓는다.

             파일 개방 모드=파일접근모드+데이터 입 출력모드

 

파일 접근 모드

모드

의미

r

    - 파일의 읽기 위해서 개방한다. 오로지 읽는 것만 가능하다.

w

-         데이터를 쓰기 위해 개방한다. 쓰는 것만 가능

-         만약에 fopen함수 호출 시 지정해 준 파일이 존재하지 않으면, 새로운 파일을 생성해서 데이터를 쓰게 된다.

-         지정해 준 파일이 존재하면, 그 파일의 데이터를 지워버리고 데이터를 쓰게 된다.

a

-         w 모드와 달리, 지정해 준 파일이 존재하면 데이터를 지우지 않고 파일의 끝에서부터 데이터를 추가한다.

-         너머지 특징은 w와 같다.

r+

-         파일을 읽고 쓰기 위해 개방한다.

-         파일이 존재하지 않는 경우, 새로운 파일을 생성한다.

-         파일이 존재하는 경우, 파일의 데이터를 지우지 않지만 원래 존재하는 파일의 데이터를 덮어쓰게 된다.

w+

-         r+ 모드와 달리, 지정해 준 파일이 존재하면 모든 데이터를 지워버리고 데이터를 기록한다.

-         나머지 특징은 r+와 같다.

a+

-         r+ 모드와 달리, 지정해 준 파일이 존재하면 파일의 끝에서부터 데이터를 추가한다. (나머지 특징은 r+와 같다.)

 

 

데이터 입출력 모드

모드

의미

t

텍스트 모드 (text mode)

b

  2진 모드(binary mode)

 

 CR(Carriage Return)

 CR은 특수문자 \r로 표현되며, 커서의 위치를 그 중 맨 앞으로 이동하라는 의미

 LF(Line Feed)

 LF \n로 표현 되며, 커서의 위치를 그 다음 줄로 이동하라는 의미이다.

 

“ABC \r DEF”  -> 출력

D

E

F

 

 

 

 

 

 

 

 

 

 

 

 

 

“ABC \n DEF”  -> 출력

A

B

C

 

 

 

 

 

 

 

 

D

E

F

 

 

“ABC \r\n DEF”  -> 출력

A

B

C

 

 

 

 

 

D

E

F

 

 

 

 

 

 

 2진 모드와 텍스트 모드

-         2진 모드: 프로그램상에서 파일로 데이터를 쓰거나 읽어 들이는 경우에 아무런 데이터의 변환도 일으키지 않는 데이터 입출력 모드를 의미한다.

-         텍스트 모드 : 프로그램상에서 파일로 데이터를 쓰거나 읽어 들이는 경우에 데이터 변환이 일어나는 입출력 모드를 의미한다.

(printf와 같은 표준 출력 함수들은 텍스트 모드로 출력하기 때문에 C에서 \n을 입력할 경우\r\n으로 변환되어 출력된다.)

 

FILE 구조체의 포인터 (파일 포인터)

-         fopen 함수의 리턴 값은 FILE이라는 구조체 변수의 포인터이다. FILE 구조체 변수는 개방한 파일에 대한 여러 가지 정보를 지니는 변수이다. 개방한 파일이 무엇인지, 파일 내에 존재하는 데이터를 어디까지 읽어 들였는지, 파일의 끝에 도달했는지에 대한 정보들을 FILE구조체 변수는 지닌다.

 

 

◊ 파일 입출력 함수

-         puts함수는 스트림이 stdout으로 미리 정해져 있지만 fputs함수는 스트림을 지정할 수 있다. 파일 포인터는 스트림을 의미한다.

 

         스트림

기능

키보드/모니터

선택(키보드/모니터,파일)

문자 출력

int putchar(int c)

int fputc(int c, FILE* stream)

문자 입력

int getchar(void)

int fgetc(FILE* stream)

문자열 출력

int puts(const char* s)

int puts(const char* s, FILE* stream)

문자열 입력

char* gets(char* s)

char* fgets(char* s, int n, FILE* stream)

형식 지정

출력

int printf(const* format,...)

int fprintf(FILE* stream,

     const char* format, …)

형식 지정

입력

int scanf(

    Const char* format,…)

int fscanf(FILE* stream,

    const char* format,..)

 

 feof 함수

 

#include <stdio.h>

 

int feof(FILE *stream)

호출 시 전달되는 파일 포인터가 가리키는 파일이 끝에 도달 할 경우 0이 아닌 값을 리턴한다.

 

◊ fseek 함수

#incldue <stdio.h>

 

int fseek(FILE *stream, long offset, int wherefrom)

파일 위치 지시자를 원하는 위치로 이동시키는 함수이다.

Stream이 가리키는 파일의 파일 위치 지시자를 시작위치 wherefrom에서부터 offset 만큼 이동한다.

 

wherefrom전달인자

whrerfrom

파일 위치 지시자를 offset 만큼 이동하기 전

SEEK_SET(0)

파일의 맨 앞으로 이동한다.

SEEK_CUR(1)

현재 위치

SEEK_END(2)

파일의 맨 끝으로 이동한다.

 

Posted by cyj4369
,

mt.exe : general error c101008a: Failed to save the updated manifest to the file ".Debug\.exe.embed.manifest". d 

솔루션을 실행해 보면 위와 같은 에러가 발생한다.


이럴 때는 라이브러리 파일의 변경이나 기타 전의 솔류션과는 다른환경일 경우에 발생하는 오류로 보여진다.


그렇기 때문에 디버그 폴더에 가서 파일들을 싹 삭제한다음에 다시 빌드를 해주면 오류가 해결되는 것을 볼 수 있다.


여기서 디버그 폴더는 솔루션 바로 밑에 있는 폴더가 아닌 프로젝트 폴더 밑에 있는 디버그 폴더안의 내용을 지워줘야 한다.

Posted by cyj4369
,
winsock을 이용한 파일 보내기(C++) 소스
 
#include<winsock2.h>
#include<stdio.h>
#include<stdlib.h>
 
#define BUFSIZE 4096
 
// 소켓 함수 오류 출력 후 종료
void err_quit(char *msg)
{
           LPVOID lpMsgBuf;
           FormatMessage(
                     FORMAT_MESSAGE_ALLOCATE_BUFFER|
                     FORMAT_MESSAGE_FROM_SYSTEM,
                     NULL, WSAGetLastError(),
                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                     (LPTSTR)&lpMsgBuf, 0, NULL);
           MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
           LocalFree(lpMsgBuf);
           exit(-1);
}
 
// 소켓 함수 오류 출력
void err_display(char *msg)
{
           LPVOID lpMsgBuf;
           FormatMessage(
                     FORMAT_MESSAGE_ALLOCATE_BUFFER|
                     FORMAT_MESSAGE_FROM_SYSTEM,
                     NULL, WSAGetLastError(),
                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                     (LPTSTR)&lpMsgBuf, 0, NULL);
           printf("[%s] %s", msg, (LPCTSTR)lpMsgBuf);
           LocalFree(lpMsgBuf);
}
 
int main(int argc, char *argv[])
{
 
    int err;
 
           if(argc < 2){
                     fprintf(stderr, "Usage: %s <FileName>\n", argv[0]);
                     return -1;
           }
 
          
           WSADATA wsa;
           if(WSAStartup(MAKEWORD(2,2),&wsa) !=0 )
                     return -1;
 
           SOCKET senderSock = socket(AF_INET,SOCK_STREAM, 0);
    if(senderSock == INVALID_SOCKET){
                                             err_quit("socket()");
                                                                                               }
          
           // connect()
           SOCKADDR_IN senderaddr;
           ZeroMemory(&senderaddr,sizeof(senderaddr));
           senderaddr.sin_family = AF_INET;
           senderaddr.sin_port = htons(9000);
           senderaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
          
           err = connect(senderSock, (SOCKADDR *)&senderaddr,sizeof(senderaddr));    
           if(err == SOCKET_ERROR) err_quit("connect()");
 
 
           //파일 열기
           FILE *fp = fopen(argv[1],"rb");
 
           if(fp== NULL)
           {
            perror("파일 입출력 오류");
            return -1;
           }
 
           //파일 이름 보내기
           char filename[256];
           ZeroMemory(filename,256);
           sprintf(filename,argv[1]);
           err = send(senderSock,filename,256,0);
           //if(err == SOCKET_ERROR) err_quit("send()");
 
 
           //파일 크기 얻기
           fseek(fp,0,SEEK_END);//파일 포인터를 파일의 끝으로 옮김
           int totalbytes = ftell(fp);
 
           printf("크기 :%d bytes\n",totalbytes); //ansi로 된 text파일에 있는 문자
 
           err = send(senderSock,(char *)&totalbytes,sizeof(totalbytes),0);
           if(err == SOCKET_ERROR) err_quit("send()");
 
 
           //파일 데이터 전송에 사용할 변수
           char buf[BUFSIZE];
           int numread;
           int numtotal = 0;
 
           //파일 데이터 보내기
 
           rewind(fp); // 파일 포인터를 제일 앞으로 이동
           while(1){
                     numread = fread(buf, 1, BUFSIZE, fp);
                     if(numread > 0){
                                err = send(senderSock, buf, numread, 0);
                                if(err == SOCKET_ERROR){
                                          err_display("send()");
                                          break;
                                }
                                numtotal += numread;
                     }
                     else if(numread == 0 && numtotal == totalbytes){
                                printf("파일 전송 완료!: %d 바이트\n", numtotal);
                                break;
                     }
                     else{
                                perror("파일 입출력 오류");
                                break;
                     }
           }
 
           fclose(fp);         
    closesocket(senderSock);
           WSACleanup();
 
return 0;
 
}
Posted by cyj4369
,
화면 처리 함수 
 
Visual C++에는 Turbo - C에서 사용할 수 있는 화면 처리 함수가 정의되어 있지 않습니다. 
이런 이유로 함수를 정의해서 이용해야 합니다. 
Turbo ? C에서는 conio.h를 인클루드 시켜 바로 사용하면 됩니다. 
gotoxy(int x, int y): x, y 좌표로 커서 이동 
wherex(): 현재 커서의 x좌표 리턴 
wherey(): 현재 커서의 y좌표 리턴 
함수를 아래와 같이 정의한 후 windows.h를 인클루드 시키면 됩니다. 
void gotoxy(int x, int y) 
     COORD Cur; 
     Cur.X=x; 
     Cur.Y=y; 
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur); 
   
 

// 커서의 x 좌표를 조사한다. 
int wherex() 
     CONSOLE_SCREEN_BUFFER_INFO BufInfo; 
   
 

     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&BufInfo); 
     return BufInfo.dwCursorPosition.X; 
   
 

// 커서의 y좌표를 조사한다. 
int wherey() 
     CONSOLE_SCREEN_BUFFER_INFO BufInfo; 
   
 

     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&BufInfo); 
     return BufInfo.dwCursorPosition.Y; 
예제23) 커서를 이동시킨 후 x 좌표와 y좌표를 출력하는 프로그램 
#include <stdio.h> 
#include <windows.h> 
void gotoxy(int x, int y) 
     COORD Cur; 
     Cur.X=x; 
     Cur.Y=y; 
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur); 
 
 

int wherex() 
     CONSOLE_SCREEN_BUFFER_INFO BufInfo; 
 
 

     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&BufInfo); 
     return BufInfo.dwCursorPosition.X; 
int wherey() 
     CONSOLE_SCREEN_BUFFER_INFO BufInfo; 
     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&BufInfo); 
     return BufInfo.dwCursorPosition.Y; 
int main() 
    int x, y; 
    gotoxy(30, 10); 
    x = wherex(); 
    y = wherey(); 
    printf("x좌표:%d y좌표:%d\n",x,y); 
    return 0; 
}
Posted by cyj4369
,