공부

20200903 공부

글로벌디노 2020. 9. 3. 16:12

1. 문제 만들기

2. 멀티스레드

1) 스레드 생성과 종료, 인자 전달 연습

2) 스레드 우선순위 변경 연습

3) 스레드 실행 제어와 종료 기다리기 연습

4) 멀티스레드 TCP 서버

 

 

 

1. 문제 만들기

 

1) x86 함수 호출 규약

(1), (2), (3) 에 해당하는 값을 채우시오.

 

규약 인자 전달 순서 인자 전달 매체 Stack을 정리하는 함수
cdecl Stack ( 2 )
stdcall ( 1 ) Stack ( 3 )
fastcall Register + Stack Callee

 

 

2) 함수 포인터

( ? ) 부분을 채워서 코드를 완성하시오

int Sum(int a, int b)
{
	return a + b;
}

int main()
{
	( ? )

	int res = FuncSum(10, 20);

	return 0;
}

 

3) 난수

rand() 함수를 사용해서 5만 ~ 10만 사이의 난수를 구하시오

 

 

4) 퀵정렬

QSort 함수를 구현하시오

#include <stdio.h>

void QSort(int* arr, int start, int end)
{
	
}

int main()
{
	int arr[] = { 5,3,1,2,4 };

	QSort(arr, 0, 4);

	for (int i = 0; i < 5; i++)
		printf_s("%d ", arr[i]);

	return 0;
}

 

 

 

정답

 

1)

(1) : ←

(2) : Caller

(3) : Callee

 

2)

int(*FuncSum)(int, int) = Sum;

 

3)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define RANDOM(__min__, __max__) ((int)(((double)((rand()<<15) | rand())) / ((RAND_MAX<<15 | RAND_MAX) + 1) * ((__max__) - (__min__))) + (__min__))

int main()
{
	srand(time(0));

	int min = 100000;
	int max = 0;

	while (1)
	{
		int rnd = RANDOM(50000, 100001);
		
		if (min > rnd)
			min = rnd;

		else if (max < rnd)
			max = rnd;

		printf_s("%d, min[%5d] max[%6d] \n", rnd, min, max);
	}

	return 0;
}

참고) https://swjman.tistory.com/26

 

4)

#include <stdio.h>

void QSort(int* arr, int start, int end)
{
	int left = start;
	int right = end;
	int pivot = arr[(left + right) / 2];

	while (left <= right)
	{
		while (arr[left] < pivot)
			++left;
		while (arr[right] > pivot)
			--right;

		if (left <= right) 
		{
			int tmp = arr[left];
			arr[left] = arr[right];
			arr[right] = tmp;
			++left;
			--right;
		}
	}

	if (left < end)
		QSort(arr, left, end);

	if (right > start)
		QSort(arr, start, right);
}

int main()
{
	int arr[] = { 5,3,1,2,4 };

	QSort(arr, 0, 4);

	for (int i = 0; i < 5; i++)
		printf_s("%d ", arr[i]);

	return 0;
}

 

 

 

2. 멀티스레드

 

1) 스레드 생성과 종료, 인자 전달 연습

 

CreateThread() / ExitThread()

_beginthreadex() / _endthreadex()

#include <Windows.h>
#include <process.h>
#include <stdio.h>

struct Vector3Int
{
	int x, y, z;
};

//DWORD WINAPI MyThread(LPVOID arg)
unsigned __stdcall MyThread(void* arg)
{
	Vector3Int* vec = (Vector3Int*)arg;
	
	while (1)
	{
		printf_s("Running MyThread() %d : %d, %d, %d \n", 
			GetCurrentThreadId(), vec->x, vec->y, vec->z);
		Sleep(1000);
	}

	// _endthreadex(0);
	return 0;
}

int main()
{
	Vector3Int vec1 = { 10, 20, 30 };

	//HANDLE hThread1 = CreateThread(NULL, 0, MyThread, &vec1, 0, NULL);
	HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, MyThread, &vec1, 0, NULL);
	if (hThread1 == NULL) return 1;
	CloseHandle(hThread1);

	Vector3Int vec2 = { 40, 50, 60 };

	//HANDLE hThread2 = CreateThread(NULL, 0, MyThread, &vec2, 0, NULL);
	HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, MyThread, &vec2, 0, NULL);
	if (hThread2 == NULL) return 1;
	CloseHandle(hThread2);

	while (1)
	{
		printf_s("Running main() %d\n", GetCurrentThreadId());
		Sleep(1000);
	}

	return 0;
}

 

결과

 

 

2) 스레드 우선순위 변경 연습

 

#include <Windows.h>
#include <stdio.h>

DWORD WINAPI MyThread(LPVOID arg)
{
	while (1);
	return 0;
}

int main()
{
	// CPU 개수를 알아낸다
	SYSTEM_INFO si;
	GetSystemInfo(&si);

	// CPU 개수만큼 스레드를 생성한다
	for (int i = 0; i < (int)si.dwNumberOfProcessors; i++)
	{
		HANDLE thread = CreateThread(NULL, 0, MyThread, NULL, 0, NULL);
		if (thread == NULL) return 1;

		// 최고 우선순위로 변경한다
		SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
		CloseHandle(thread);
	}


	Sleep(1000);

	while (1)
	{
		printf_s("메인 스레드 실행!\n");
		break;
	}

	return 0;
}

 

위 코드를 실행하면 컴퓨터가 멈춘다! ( 깜놀.. )

컴퓨터 재부팅하지 말고 기다리면 프로그램 종료 된다

 

윈도우 운영체제에서는 오랜 시간 CPU 시간을 할당받지 못한 스레드의 우선순위를 단계적으로 끌어올리기 때문에 main 스레드도 실행할 기회를 얻는다

 

 

 

3) 스레드 실행 제어와 종료 기다리기 연습

 

WaitForSingleObject

SuspendThread / ResumeThread

#include <Windows.h>
#include <process.h>
#include <stdio.h>

int sum = 0;

unsigned __stdcall MyThread(void* arg)
{
	int num = *(int*)arg;
	
	for (int i = 1; i <= num; i++)
		sum += i;

	return 0;
}

int main()
{
	int num = 100;

	HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, MyThread, &num, CREATE_SUSPENDED, NULL);
	if (thread == NULL) return 1;

	printf_s("스레드 실행 전, 계산 결과 = %d\n", sum);

	ResumeThread(thread);
	WaitForSingleObject(thread, INFINITE);

	printf_s("스레드 실행 후, 계산 결과 = %d\n", sum);
	CloseHandle(thread);

	return 0;
}

 

 

WaitForMultipleObjects

#include <Windows.h>
#include <process.h>
#include <stdio.h>

unsigned __stdcall MyThread(void* arg)
{
	int count = *(int*)arg;

	for (int i = 1; i <= count; i++)
	{
		printf_s("[%d] %d \n", GetCurrentThreadId(), i);
		Sleep(100);
	}

	return 0;
}

int main()
{
	int count1 = 5;
	int count2 = 10;

	HANDLE threads[2];

	threads[0] = (HANDLE)_beginthreadex(NULL, 0, MyThread, &count1, 0, NULL);
	if (threads[0] == NULL) return 1;

	threads[1] = (HANDLE)_beginthreadex(NULL, 0, MyThread, &count2, 0, NULL);
	if (threads[1] == NULL) return 1;

	WaitForMultipleObjects(2, threads, TRUE, INFINITE);

	CloseHandle(threads[0]);
	CloseHandle(threads[1]);

	printf_s("메인 스레드 종료\n");

	return 0;
}

 

 

 

4) 멀티스레드 TCP 서버

 

에코서버 코드 수정

#include <process.h>

constexpr int bufSize = 256;

// 클라이언트 연결되면 실행시킬 스레드함수
unsigned __stdcall ProcessClient(void* arg)
{
	SOCKET clientSock = (SOCKET)arg;
	SOCKADDR_IN clientAddr;
	int addrLen = sizeof(clientAddr);
	
	int ret;
	char buf[bufSize + 1];

	// 클라이언트 정보 얻기
	getpeername(clientSock, (SOCKADDR*)&clientAddr, &addrLen);

	// 데이터 수신 및 반송
	while (1)
	{
		ret = recv(clientSock, buf, bufSize, 0);
		if (ret == 0)
		{
			printf_s("connection close\n");
			break;
		}
		else if (ret < 0)
		{
			printf_s("recv failed: %d\n", WSAGetLastError());
			break;
		}

		buf[ret] = '\0';
		char addr[32];
		inet_ntop(clientAddr.sin_family, &clientAddr.sin_addr, addr, sizeof(addr));
		printf_s("[TCP/%s:%d](%3d) %s\n", addr, ntohs(clientAddr.sin_port), ret, buf);

		ret = send(clientSock, buf, ret, 0);
		if (ret == SOCKET_ERROR)
		{
			printf_s("send failed with error: %d \n", WSAGetLastError());
			break;
		}
	}

	closesocket(clientSock);
}

////////////////////////////////
// 서버 main
while (1)
{
	puts("연결 대기...");

	// accept()
	clientSock = accept(servSock, (SOCKADDR*)&clientAddr, &addrLen);
	if (clientSock == INVALID_SOCKET)
	{
		printf_s("error accept()\n");
		break;
	}

	// 연결된 클라이언트 정보 출력
	char buf[bufSize];
	InetNtopA(clientAddr.sin_family, &clientAddr.sin_addr, buf, bufSize);

	printf_s("client addr : %s, port : %d \n", buf, ntohs(clientAddr.sin_port));

	HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, ProcessClient, (void*)clientSock, 0, NULL);
	if (thread == NULL)
		closesocket(clientSock);
	else
		CloseHandle(thread);
}

 

서버 윈도우

 

클라이언트1

 

클라이언트2

 

 

 

'공부' 카테고리의 다른 글

20200905 공부  (0) 2020.09.05
20200904 공부  (0) 2020.09.04
20200902 공부  (0) 2020.09.02
20200901 공부  (0) 2020.09.02
20200831 공부  (0) 2020.09.01