묻고 답해요
150만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
순위 정보를
불러오고 있어요
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part5: UE5 & IOCP 서버 연동
언리얼 에디터 Stop버튼
selected viewport나 new editor window로 실행 했을 때Stop 버튼을 눌러도 연결이 끊어지지 않고언리얼 에디터까지 꼭 종료해줘야 끊어지더라구요.stop버튼을 눌렀을 때 종료되는 것처럼 하려면 어떻게 해야 하나요??standalone game으로 해봤을 때 제가 원하는 대로 동작해주긴 했는데위에 두가지 경우에도 방법이 있을까 해서 질문드립니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part5: UE5 & IOCP 서버 연동
질문 있습니다...
혹시 만약에 인벤토리을 관리할떄 서버가 아닌 클라에서 아이템 관리를 위해 아이템객체들을 전부 스마트포인터를 써야할지... 포션같은 소모아이템 떄문에 써야되지 않을까 하는데 너무 고민입니다. 현업에서도 GC를 적극적으로 사용을 하는지서버가 있는데 AI 인공지능을 쓰는 경우가 있다면 어느 경우인지 이렇게 질문 3개입니다...
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part5: UE5 & IOCP 서버 연동
클라이언트 강제 종료 시 플레이어 삭제 기능
안녕하세요 루키스님part4 강의로 만들어진 서버와part5에서 만들어진 클라이언트를조금 수정해가며 추가 기능을 만들던 중문제가 생겼는데 해결이 잘 안되어서 질문드립니다.우선 추가하려는 기능은 강의에서 배운 Q를 눌러서 종료하는 기능 외에플레이어(3명)들이 접속해있는 상태에서 언리얼 편집창을 닫아버렸을 때3명 모두 접속이 끊어지며 플레이어들을 서버에서 제거해주는 기능을 추가하려고 합니다..이 때, 발생하는 문제는player가 3명이고 objectId가 각각 1번부터 3번까지 있다고 했을 때,어쩔 땐 player들 모두 제거되고,어쩔 땐 player(2번), player(1번), player(1번)처럼objectId가 1번인 플레이어를 제거하는 처리가 중복 호출되며2번과 1번에 대한 삭제만 이루어지고,3번에 대한 삭제가 이루어지지 않는 문제가 발생합니다.아래는 작성한 코드입니다.먼저 GameSession::OnDisconnected()의 맨 마지막 줄에 GRoom->DoAsync()로Room::HandleLeavePlayer를 호출해주는 코드를 추가했고,이 때 들어오는 player들의 objectId들을 확인해봤을 때1, 2, 3 모두 중복 없이 들어오는 것을 확인했습니다.void GameSession::OnDisconnected() { if (player.load() == nullptr) { return; } cout << "objectId: " << player.load().get()->objectInfo->object_id() << endl; RoomRef room = player.load()->room.load().lock(); if (room == nullptr) { return; } GRoom->DoAsync(&Room::HandleLeavePlayer, player.load()); }다음은 Room::LeaveRoom()에서 위에서 말한 상황일 때파라미터로 들어오는 object가 중복으로 들어오는 걸 확인했습니다.if(!success) { return success; }는이미 삭제된 object를 중복으로 RemoveObject(objectId)를 할 경우 false를 돌려주는데밑에서 패킷 보내는 작업을 넘겨버리기 위해 추가했습니다.그리고 코드 거의 마지막 부분에GSessionManager.Remove(session)로세션을 제거하는 코드를 추가했습니다.bool Room::LeaveRoom(ObjectRef object) { if (object == nullptr) { return false; } const uint64 objectId = object->objectInfo->object_id(); bool success = RemoveObject(objectId); if (!success) { return success; } // 퇴장할 플레이어에게 퇴장 패킷 전송 if (object->IsPlayer()) { PlayerRef player = static_pointer_cast<Player>(object); Protocol::S_LEAVE_GAME leavePkt; SendBufferRef sendBuffer = ClientPacketHandler::MakeSendBuffer(leavePkt); if (GameSessionRef session = player->session.lock()) { session->Send(sendBuffer); } } // 남아있는 플레이어들에게 퇴장 플레이어의 디스폰 패킷 전송 { Protocol::S_DESPAWN despawnPkt; despawnPkt.add_object_ids(objectId); SendBufferRef sendBuffer = ClientPacketHandler::MakeSendBuffer(despawnPkt); Broadcast(sendBuffer, objectId); // 퇴장 플레이어는 이미 room에서 빠져나간 상태라 Broadcast 불가 if (object->IsPlayer()) { PlayerRef player = static_pointer_cast<Player>(object); if (GameSessionRef session = player->session.lock()) { session->Send(sendBuffer); GSessionManager.Remove(session); } } } return success; } GameSession 소멸자virtual ~GameSession() override { cout << "~GameSession" << endl; player.store(shared_ptr<Player>()); }Player 소멸자Player::~Player() { cout << "~Player" << endl; session.reset(); }다음은 첫번째 실행 화면입니다.(실행 화면에 출력되는 줄이 뒤죽박죽이라 서로 다른 색으로 구별 해봤습니다..ㅠ)연두색으로 묶은 범위는 언리얼 에디터를 1번 실행했다가 닫았을 때의 단위로 묶었습니다.빨간색으로 밑줄 그어진 objectId: 숫자로 출력되는 부분은GameSession::OnDisconnected()에서 출력하고 있고,노란색으로 밑줄 그어진 Remove Objedct숫자로 출력되는 부분은Room::RemoveObject()에서 objectId를 출력하고 있습니다.첫번째 실행 화면에서는 처음 실행하고 바로 해당 문제가 발생했습니다.objectId: 3, objectId: 2, objectId: 1 순으로 중복 없이 잘 들어왔는데Remove Object3, Remove Object1, Remove Object1 처럼 출력되었고,2번 플레이어에 대한 제거가 되지 않았습니다.때문에 두번째, 세번째 실행에서는 접속한 3명의 플레이어가 모두 잘 제거됨에도처음에 제거되지 않은 플레이어 하나가 남아서언리얼 에디터 실행 화면에 보이는 플레이어가 총 4명이었습니다.다음은 두번째 출력 화면입니다.두번째 실행 화면에서는 5번째가 되어서야 해당 문제가 발생했습니다.그 전까지는 문제 없이 3명의 플레이어 모두 잘 제거되었습니다.마찬가지로 objectId: 13, objectId: 14, objectId: 15로 들어왔고Remove Object13, Remove Object15, Remove Object15로 실행되면서13, 15번의 플레이어만 제거되고 14번 플레이어는 제거되지 않았습니다.실제로 문제가 발생할 경우의 호출 스택을 따라가 봤을 때 OnDisconnected()에서GRoom->DoAsync(&Room::HandleLeavePlayer, player.load())로삭제 작업 예약 거는 것 까지는 플레이어가 중복 없이 잘 들어가는데예약했던 Room::HandleLeavePlayer()가 호출되고파라미터로 들어오는 플레이어의 objectId를 확인해보면이미 삭제된 플레이어가 한번 더 들어오는 경우가 생기네요.혹시 어떤 부분 때문일까요??
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
소멸자 부분에서 ref 변수들을 release 하는건 좋지 못한가요?
이번 강의는 순환 참조일 때 한 객체가 소멸될 시 참조하고있는 객체에 관해 refCount가 줄지않아 문제가 생기는 것에 관해서 여러 방법을 알려주시는것 같았습니다. 그렇다면 소멸자 부분에서 자신이 참조하고 있는 객체들을 release해주는것은 어떤가요?참조하는 객체가 많으면 유지보수하기 어려울것 같은데 그래도 이것 또한 해결책이 될 수 있나요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
writeCount는 원자성 보장하지 않아도 되나요??
writeCount는 atomic이 아닌 일반 uint16이고writeLock++;writeLock--;같은 증감 연산자를 할 때 따로 임계구역 만들지 않는것 처럼 보입니다. 이러면 진짜 만약에 두 개 이상의 쓰레드가 동시에 증감연산을 하게될 경우 이전에 해봤던 예제처럼uint16 temp = writeLock;temp++;writeLock = temp;이렇게 3단으로 실행이 되서 조금씩 오차가 생길 수 있을것 같은데 이 부분은 따로 고려하지 않아도 충분한가요??
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
static TypeConversion conversion, template argument 없는 경우
준비해주신 강의자료TypeCast.h153번줄에 있는 선언에 대한 질문입니다. static inline bool CanConvert(int32 from, int32 to){static TypeConversion conversion;return s_convert[from][to];} CanConvert 함수안에 있는 TypeConversion 타입의정적변수 선언이 문법적으로 잘 이해가 가지 않습니다 TypeConversion은 class template이기 때문에선언할 때 template argument값(=typeList)을 줘야 한다고 생각했습니다.(제가 생각했던 예시)ex) static TypeConversion<TL> conversion; 근데 예시 코드에는 생략하여도 잘 동작해서관련해서 어떤 문법인지 찾으려고 했는데 찾지 못했습니다 개인적으로 열심히 고민해봤는데 default type이 정해진 경우에 생략이 가능하고template function에는 인자 값을 통해 추론해템플릿 인자값을 생략하는 경우도 있었지만둘 다 해당하지 않는 것 같습니다 TypeConversion<TL>::CanConvert(ptr->_typeId, IndexOf<TL, remove_pointer_t<To>>::value)를 통해서 이미 template class가 인자 값을 받아서인스턴트화 했기 때문에 생략이 가능한 것으로 이해해도 괜찮을까요? -수정Injected-class-name 라는 cpp reference를 찾았습니다제가 궁굼해 하는게 이게 맞을까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Event와 Condition Variable 중에 헷갈리는 부분이 있어서 질문드립니다
안녕하세요 선생님. 이전 강의인 Event와 비교했을 때 헷갈리는 부분이 있어서 질문 드립니다. EventEvent를 사용하면 Lock코드와 묶여있지 않기 때문에 Producer 쓰레드가 연달아 Lock을 가져가게 될 경우에 q의 값이 누적되어 값이 틀어질 수 있다고 하셨던 것으로 이해했습니다.아래는 Event 강의의 코드인데요, Consumer 함수에서 if(!q.empty())를 while(!q.empty())로 변경했을 때 q의 크기가 4자릿수로 넘어가는 경우는 발생하지 않는 반면에, 조건변수를 사용하면 q의 크기가 4자릿수가 넘어갈 때가 심심찮게 발생합니다. CPU사용량은 거의 비슷합니다.강의 설명에서는 Kernel Object와 User-Level Object의 차이때문에 Event보다 조건변수를 사용하는 것이 효율적이라는 뉘앙스로 느껴집니다. 물론, 이전 가르침을 통해서 상황에 따라 효율적인 방식은 전부 다르겠지만, 이번의 경우는 예외처럼 느껴져서 질문드립니다. 조건변수가 더 효율적인 방식인가요?#include "pch.h" #include <iostream> #include "CorePch.h" #include <thread> #include <atomic> #include <mutex> #include <windows.h> mutex m; queue<int32> q; HANDLE handle; void Producer() { while (true) { { unique_lock<mutex> lock(m); q.push(100); } ::SetEvent(handle); this_thread::sleep_for(100ms); } } void Consumer() { // 데이터를 꺼내 쓰고 있음 while (true) { ::WaitForSingleObject(handle, INFINITE); // 현재 상태가 ManualReset이면 수동으로 Non-Signal로 바꿔줘야 함. //::ResetEvent(handle); unique_lock<mutex> lock(m); if (!q.empty()) { int32 data = q.front(); q.pop(); cout << data << '\n'; } } } int main() { handle = ::CreateEvent(NULL/*보안속성*/, FALSE/*bManualReset*/, FALSE/*bInitialState*/, NULL); thread t1(Producer); thread t2(Consumer); t1.join(); t2.join(); ::CloseHandle(handle); }
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
이벤트를 쓰는 것이 CPU 처리율이 더 높게 나오는데 무엇이 문제인지 모르겠습니다
안녕하세요 선생님 🙂 선생님 강의 덕분에 서버에 입문을 수월하게 한 것 같습니다. 감사합니다 ^^ 다름이 아니라, 이벤트를 쓰면 WaitForSingleObject 함수로 인해서 계속해서 대기가 되는 상태일텐데 CPU 점유율이 쓸데없이 무한루프를 도는 것보다 많이 먹습니다. 무엇이 문제인지 잘 모르겠습니다 ㅠㅠ 확인해주시면 감사하겠습니다!!<이벤트 사용X> <이벤트 사용O>
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
몬스터 충돌판정
안녕하세요 강의를 보고 배운 서버와 dx11로 3d게임을 만들어 보고있습니다. 이동동기화 등은 잘 됬고 몬스터를 만들었는데 접속한 클라에서 모두 동일하게 로직이 돌아가야하니 몬스터의 로직은 서버에서 돌아가게 만들었습니다. 그런데 플레이어가 몬스터를 타격하면 타격한 플레이어가 타격했다는 패킷을 보내고 플레이어가 플레이어를 타격하면 피격당한 플레이어가 패킷을 보내는 식으로 했는데 투사체 같은경우 몬스터가 투사체를 맞았다 라는건 서버에서도 충돌체를 두고 몬스터가 검증을 해야할까요? 클라에서 판단하더라도 그러면 여러 클라가 있을경우 여러 클라가 다 맞았다는 패킷을 보낼것 같아 뇌가 꼬입니다...물론 방법이야 많겠지만 이부분 구현에 있어 감이 안잡혀 질문드립니다 ㅠㅠ
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
memoryPool class관련 질문입니다,.
지금 영상을 보며 클론코딩중에 다소 이해가 안되는 부분이 있어 질문드립니다. MemoryPool::Pop()에서 header == nullptr 인 경우에할당해주는 mem 크기가 _allocSize로 되어 있는데 이 경우 MemoryHeader의 크기까지 반영해야 하는게 아닌지 질문드립니다. header = reinterpret_cast<MemoryHeader*>(::malloc(sizeof(MemoryHeader) + _allocSize));위에 코드처럼 수정을 해야 반환된 heaer가 이후에 MemoryClass에서 AttachHeader를 해줄때 MemoryHeader 크기만큼 포인터 이동이 가능해지는게 아닌가 생각합니다.
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
TSharedPtr<Wraight>의 스레드 안정성있는 삭제 방법
이전 질문들과 겹치는 것을 알고 있으나, 코드 테스트 이후에도 아래와 같은 의문이 풀리지 않아 글을 쓰게 되었습니다. 의문: 전역변수로 지정된 TSharedPtr<RefCountable변수형> "몬스터"가 있습니다. 이를 타 스레드에서 는 복제하여 사용하는 도중, 메인 스레드에서 "몬스터"를 이제 제거하고 싶어 nullptr을 대입합니다. 이때 아래와 같은 문제가 발생합니다.int32 ReleaseRef() { int32 refCount = --_refCount; // 타 스레드에서 이 타이밍에 "몬스터" 복제하는 문제 if (refCount == 0) { delete this; } return refCount; } 실제 테스트:class Wraight : public RefCountable { public: int testValue = 0; }; using WraightRef = TSharedPtr<Wraight>; class Missile : public RefCountable { public: void SetTarget(WraightRef target) { _target = target; // GWraight가 이미 완전히 삭제된 이후 생성된 경우, nullptr 오류 방지 if (!_target.IsNull()) _target->testValue = 5; } private: WraightRef _target; }; using MissileRef = TSharedPtr<Missile>; // 스레드들 접근가능한 전역변수 WraightRef GWraight; int main() { // 10번 실험 for (int i = 0; i < 10; i++) { // 타겟 소환 GWraight = (new Wraight); GWraight->ReleaseRef(); // 100'000개의 수많은 미사일 생성 및 타겟 지정 thread t1([]() { for (int i = 0; i < 100'000; i++) { MissileRef missile(new Missile()); missile->ReleaseRef(); missile->SetTarget(GWraight); } }); // 타겟 1ms 뒤에 소멸 thread t2([]() { this_thread::sleep_for(1ms); GWraight = nullptr; }); t1.join(); t2.join(); this_thread::sleep_for(3000ms); } }해당 코드 실행 이후, 아래와 같은 문제점이 생겼습니다. 케이스A미사일 발사 후, 제거되는 ~MissileRef()의 ReleaseRef() 내부 delete에서 오류가 발생 합니다. 예상되는 원인:int32 ReleaseRef() { int32 refCount = --_refCount; if (refCount == 0) { // 1. 타 스레드에서 복제 delete this; // 2. 복제된 객체는 이미 삭제된 _ptr을 들고있음 // 3. 복제에 따라 _refCount = 1 } return refCount; } // 4. 이후에 복제된 객체 삭제되면서 refCount = 0 // 5. 이중 delete 실행 -> 오류 케이스B타겟인 GWraight가 TSharedPtr<Wraight>(nullptr)를 복사할 때, ReleaseRef() 내부 delete에서 오류가 발생 합니다. 예상되는 원인:int32 ReleaseRef() { int32 refCount = --_refCount; if (refCount == 0) { // 1. 타 스레드에서 복제 // 2. 복제에 따라 _refCount = 1 // 3. 이후에 복제된 객체 삭제되면서 refCount = 0 // 4. delete 실행 delete this; // 5. 이중 delete 실행 -> 오류 } return refCount; } 다른 질문에서 refCount가 0이 될 때, 참조 객체가 남아있는 것은 TSharedPtr로 구현되었을 경우 발생하지 않는 문제라고 하셨습니다. 하지만, 어떤 구조로 객체를 삭제해야 위와 같은 문제가 발생하지 않는지 감이 오지 않습니다...
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part5: UE5 & IOCP 서버 연동
52분에 나온 얘기..
52분에 나온 레플리케이션, RPC 등등 지난번에 했다라는게[입문자를 위한 UE5] Part4. 언리얼 엔진 C++에서 언리얼 네트워크 파트를 말하는 것인지 아니면 다른 어떤 강의를 말씀하시는건지.. 이 네트워크 파트에서 데디서버도 설명을 하는건가요? 데디서버도 궁금해서요... c++ part4 서버강의 들었고 언리얼로 서버 연동을 안하고 컨텐츠만 만들어봤는데 UE5 소스코드 분석 시리즈 #2 (네트워크) 이 강의 바로 들어도 상관없을까요?
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
WriteUnlock을 잘 못 호출하는 경우에 대해서
일반 Lock을 쓸 때 Unlock을 한번 더 호출해버리는 실수는 크래시가 뜨기에, 디버깅으로 알아채기 쉬운 부분이라고 생각합니다. void Lock::WriteUnlock() { if ((_lockFlag.load() & READ_COUNT_MASK) != 0) // Thread id를 체크하지 않음. Read가 없는 상황에서 WriteUnlock()이 통과할 수 있음. CRASH("INVALID_UNLOCK_ORDER"); const int32 lockCount = --_writerCount; if (lockCount == 0) _lockFlag.store(EMPTY_FLAG); }하지만, WriteUnLock() 에서는 아래와 같은 경우에 문제가 있을 수 있다고 생각합니다. // 실수로 호출 WriteUnlock(); // _writerCount = -1 // 크래시 없이 작업 진행 WriteLock(); // _writerCount = 0, 스레드 id 등록 WriteLock(); // _writerCount = 1 WriteUnlock(); // _writerCount = 0, 스레드 id 해제 WriteUnlock(); // _writerCount = -1 /***** 오랜 작업 뒤 ******/ WriteLock(); // _writerCount = 0, 스레드 id 등록 WriteUnlock(); // _writerCount = -1 // 타 스레드 접근 ReadLock(); /*or*/ WriteLock(); // 틱 시간 초과로 CRASH의 드문 경우에 한해서 수많은 코드 작업이 이뤄진 뒤라, 어디서 실수가 발생했는지 디버깅이 어려워질 것 같습니다.크게 신경 쓰지 않아도 되는 건지, 아니면 놓치고 있는 부분이 있는 것인지 궁굼합니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Lock-Free Stack #2 강의 질문
TryPop에서 compare_exchange_weak를 지난 시점에서 oldHead에 저장된 노드는 나만 가지고 있는게 아닌가요? 다른 애들은 접근하려고해도 이미 head가 바뀌어서 compare_exchange_weak를 통과하지 못하고 다음 것을 가져오는게 아닌가요?
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
메모리 정책 Release와 Acquire의 사이의 코드 재배치의 경우 어떻게 작동하나요?
Release는 이전 코드들이 뒷 줄로 코드 재배치되는 것을, Acquire은 뒷 줄 코드들이 이전으로 재배치되는 것을 막아준다고 배웠습니다.#include <atomic> #include <iostream> atomic<bool> ready; int value; void Producer() { value = 10; ready.store(true, memory_order::memory_order_release); value = 7; // ready.store() 위로 코드 재배치 가능 or 불가능 } void Consumer() { value = 0; // ready.load() 아래로 코드 재배치 가능 or 불가능 while (ready.load(memory_order::memory_order_acquire) == false) ; cout << value << endl; } int main() { // 스레드 실행 코드... 생략 }이런 value = 7과 value = 0 코드의 경우에는 코드 재배치가 일어날 위험이 있는 건가요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
TLS 는 데이터를 힙영역에서 가져갈때 깊은복사가 일어납니까 얕은복사가 일어납니까?
TLS 는 데이터를 힙영역에서 가져갈때 깊은복사가 일어납니까 얕은복사가 일어납니까?점유를 해야하니 느낌상 얕은복사일것같긴한데, lock을 하는거면 깊은복사를 하는것같기도하고... 어떻게 작동하는지 여쭙고싶습니다
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
WaitForSingleObject의 Auto reset 처리는 원자적인가요
auto_reset가 설정된 event를 SetEvent()할 때, WaitForSingleObject()로 sleep 중인 스레드들을 실행시켜주고 다시 Signal이 리셋되는 것으로 이해했습니다.여기서 Signal을 확인하고 리셋하는 과정이 CAS같이 원자적으로 동시에 작동하나요? 아니면, 중도에 WaitForSingleObject()를 호출한 스레드 측에서 리셋이 되지 않아 통과할 가능성이 있나요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
패킷직렬화 암호
간결하게 얘기하자면 패킷직렬화하고 클라나 서버로 보낼떄 패킷을 암호화처리를 하여서 보내야하는것으로 알고있는데 Protobuf에서 자체적으로 암호화처리를 하고 보내는건가요? 아니면 Protobuf와 별개로 암호화처리를 해줘야하는건가요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
MAX_NUMBER를 1'000'000까지 하면 답이 안나오는데 혹시 어떤게 문제인지 봐주실 수 있나요?
1,000번이나 100'000번까지 하면 바로 답이 나오는데 100만번으로 설정하면 계속 기다려도 감감무소식이라서 문제를 잘 모르겠습니다 ㅠㅠ. #include "pch.h" #include "CorePch.h" #include "CoreMacro.h" #include "ThreadManager.h" #include <iostream> // 소수 구하기 // 1과 자기 자신으로만 나뉘면 그것을 소수라고 함. Mutex m; bool CalculateRepeatToSelf(int32 selfNum) { int8 count = 0; for (int32 i = 2; i <= selfNum; i++) { if (count > 2) return false; if (selfNum % i == 0) { count++; } } if (count == 1) return true; return false; } int32 PreCalcuate(int32 order, int32 devision, int32 interval) { // 1, 10, 100'000 // 2, 10, 100'000 // 3, 10, 100'000 // ... // 10, 10, 100'000 int32 startNum = (order - 1) * interval + 1; int32 endNum = order * interval; int32 count = 0; for (int32 i = startNum; i <= endNum; i++) { if (CalculateRepeatToSelf(i)) count++; } return count; } int main() { const int MAX_NUMBER = 1'000'000; //const int MAX_NUMBER = 10'000; // 1229 //const int MAX_NUMBER = 1'000; // 168 // 1~MAX_NUMBER까지 소수 개수 // 멀티스레드로 병렬로 구해서 덧셈한다. /*for (int32 i = 1; i <= 20; i++) { if (CalculateRepeatToSelf(i)) count++; } cout << count << endl;*/ // ------------------------ vector<thread> threads; int32 devision = thread::hardware_concurrency(); int32 interval = MAX_NUMBER / devision + 1; atomic<int32> totalCount = 0; for (int32 i = 1; i <= devision; i++) { threads.push_back(thread([&totalCount, i, devision, interval](){ totalCount+= PreCalcuate(i, devision, interval); })); } for (thread& t : threads) { t.join(); } cout << "Total: " << totalCount.load() << endl; }
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
GetTickCount64() 의 정밀성
#include "pch.h" #include "CorePch.h" #include <iostream> #include <atomic> #include <thread> #include <mutex> #include <Windows.h> #include <future> int32 buffer[10'000][10'000]; int main() { memset(buffer, 0, sizeof(buffer)); // 배열을 전부 0값으로 초기화 //! [i][j] 순으로 더하기 { uint64 start = GetTickCount64(); //~ 시작 시간 측정 int64 sum = 0; for (int32 i = 0; i < 10'000; i++) for (int32 j = 0; j < 10'000; j++) sum += buffer[i][j]; uint64 end = GetTickCount64(); // ~ 종료 시간 측정 cout << "Elapsed Time [i][j] : " << (end - start) << endl; } //! [j][i] 순으로 더하기 { uint64 start = GetTickCount64(); //~ 시작 시간 측정 int64 sum = 0; for (int32 i = 0; i < 10'000; i++) for (int32 j = 0; j < 10'000; j++) sum += buffer[j][i]; uint64 end = GetTickCount64(); // ~ 종료 시간 측정 cout << "Elapsed Time [j][i] : " << (end - start) << endl; } }해당 코드를 7900 CPU 에서 테스트하는데, 경과시간이 둘 다 0,0 이 나오더군요.. 분명 그럴수가 없는데, CPU클럭이 너무 빨라서 gettick64() 의 정밀도로 측정이 불가능해서그런건가요? 분명 두번째 스코프에 있는 경과시간이 더 느리게 나와야 정상인데, 둘 다 틱이 0 0 이 나와서 당황스럽습니다
주간 인기글
순위 정보를
불러오고 있어요