오늘의 코드카타
상담원 인원
- 그리디를 활용한 인원 분배
- 우선순위 큐를 활용한 시간 계산
- LV3 - 16%
-> 문제 풀이
오늘의 공부
문 액터 만들기
1. 인터렉션 컴포넌트 만들기
IMC_Interaction와 IA_Interact를 선언해서 입력을 연결
- 라인트레이스를 통해 검사한 후에 인터페이스를 통해
Interact() 실행
// EGInteractionComponent.cpp
void UEGInteractionComponent::SetupInput()
{
if (ACharacter* Character = Cast<ACharacter>(GetOwner()))
{
if (APlayerController* PC = Cast<APlayerController>(Character->GetController()))
{
if (ULocalPlayer* LocalPlayer = PC->GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
if (IMC_Interaction)
{
Subsystem->AddMappingContext(IMC_Interaction, 0);
}
}
}
if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PC->InputComponent))
{
if (IA_Interact)
{
EIC->BindAction(IA_Interact, ETriggerEvent::Started, this, &UEGInteractionComponent::HandleInteract);
}
}
}
}
}
void UEGInteractionComponent::PerformInteraction()
{
AActor* Owner = GetOwner();
if (!Owner) return;
FVector StartLoc = Owner->GetActorLocation();
FVector ForwardVec = Owner->GetActorForwardVector();
FVector EndLoc = StartLoc + ForwardVec * TraceDistance;
FHitResult Hit;
FCollisionQueryParams Params;
Params.AddIgnoredActor(Owner);
if (GetWorld()->LineTraceSingleByChannel(Hit, StartLoc, EndLoc, ECC_Visibility, Params))
{
if (AActor* HitActor = Hit.GetActor())
{
if (HitActor->GetClass()->ImplementsInterface(UEGInteractInterface::StaticClass()))
{
IEGInteractInterface::Execute_Interact(HitActor);
}
}
}
DrawDebugLine(GetWorld(), StartLoc, EndLoc, FColor::Green, false, 3.f, 0, 2.f);
}
2. 인터랙트 인터페이스 생성
class EG_API IEGInteractInterface
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interact")
void Interact();
};
3. 문 액터 생성
- 인터랙트 인터페이스 기반으로 문 열고 닫히는 액터 생성
- 타임라인 활용해서 액터 로테이션 설정
-> 타임라인은 왠만하면 블루프린트를 활용하자..
// EGDoor.h
UPROPERTY()
UTimelineComponent* DoorTimeline;
UPROPERTY(EditAnywhere)
UCurveFloat* DoorCurve;
// EGDoor.cpp
void AEGDoor::BeginPlay()
{
Super::BeginPlay();
if (DoorCurve)
{
FOnTimelineFloat InterpFunction;
InterpFunction.BindUFunction(this, FName("HandleDoor"));
DoorTimeline->AddInterpFloat(DoorCurve, InterpFunction);
DoorTimeline->SetLooping(false);
}
}
void AEGDoor::Interact_Implementation()
{
if (DoorTimeline->IsPlaying())
{
DoorTimeline->Reverse();
}
else
{
if (bIsOpen)
{
DoorTimeline->ReverseFromEnd();
}
else
{
DoorTimeline->PlayFromStart();
}
}
bIsOpen = !bIsOpen;
}
오늘의 CS
컨텍스트 스위칭
- 컨텍스트
- CPU가 처리하는 프로세스나 스레드의 현재 실행 상태
- 어디까지 실행했는지, 어떤 자원을 쓰고 있는지를 저장한 정보
- 개념
- 운영체제가 CPU를 여러 프로세스/스레드를 번갈아 사용할 수 있도록 하는 기술
- 멀티 프로세스 환경에서 CPU가 처리 중인 프로세스의 정보를 바꾸는 것
- 레지스터에 로드하는 동안 CPU가 일을 못하기 때문에 오버헤드가 발생
- 실행 과정
- CPU가 P1을 처리하던 중 OS에 의해 인터럽트 발생
- CPU 스케줄러는 레지스터에 있는 실행 중이던 프로세스의 상태를 PCB(Process Control Block)에 저장
- P2의 PCB에 있는 정보를 가져와 레지스터에 로드하고 CPU는 P2를 처리함
- P2 처리가 끝나면 다시 P1을 레지스터에 로드하고 프로세스를 계속 실행

- PCB(Process Control Block)
- OS가 프로세스를 관리하는 데 필요한 모든 정보를 담고 있는 자료구조
- 각각의 프로세스는 고유한 PCB를 가지며, 프로세스가 생성될 때 함께 만들어지고 종료되면 사라짐
- 레지스터 값, 프로그램 카운터, 스택 포인터 등을 저장
- 오버헤드
- 레지스터 값 저장 / 복원 -> CPU 시간 소모(일 못함)
- 캐시 메모리 : 다른 프로세스의 데이터로 덮이면 이전 프로세스의 데이터가 캐시에서 사라짐
-> 다음에 접근할 때 RAM에서 다시 로드 필요 (캐시 미스 발생)
- TLB : 프로세스 전환 시 다른 페이지 테이블을 쓰면 TLB 매핑이 무효화되어 다시 페이지 테이블을 읽어와야 함
- 프로세스 컨텍스트 스위치 vs 스레드 컨텍스트 스위치
- 프로세스 컨텍스트 스위치
- 가상 메모리 주소 공간까지 바꿔야 함 -> 페이지 테이블 교체 필요, TLB 대량 무효화 필요
- 스레드 컨텍스트 스위치
- 같은 가상 메모리 주소 공간 공유 -> 페이지 테이블 교체 불필요, TLB 변환 필요 없음
-> 스레드 전환은 동일한 가상주소 공간을 공유하므로 메모리 변환 캐시와 주소공간 관련 오버헤드를 피할 수 있어서 훨씬 비용이 싸다.