volatile

변수의 값을 캐시에 저장하지 않고 항상 메모리에서 값을 읽어오도록 한다.

멀티 스레딩 환경에서 여러 스레드가 동시에 하나의 변수에 접근할 때 캐시에 저장된 값과 메모리의 실제 값이 일치하지 않아서 오류가 발생할 수 있다.

 

int counter = 0;

void IncrementCounter()
{
    for (int i = 0; i < 100000; i++)
    {
        counter++;
    }
}

void DecrementCounter()
{
    for (int i = 0; i < 100000; i++)
    {
        counter--;
    }
}

void Main()
{
    Thread t1 = new Thread(IncrementCounter);
    Thread t2 = new Thread(DecrementCounter);

    t1.Start();
    t2.Start();

    t1.Join();
    t2.Join();

    Console.WriteLine("Counter value: " + counter);
}

 

위 코드에서 counter변수에 서로 다른 스레드에서 거의 동시에 접근하여 값을 변경하고 있다.

이때 counter는 항상 0이 아니며 일정하지 않은 값들로 출력된다.

 

이러한 상황에서 volatile 키워드로 변수를 선언하면 항상 일정한 값이 들어오게 된다.

 

int volatile counter = 0;

 

728x90
반응형

'Program Language > C#' 카테고리의 다른 글

C# 고정소수점 키워드 : decimal  (0) 2023.04.25
C# Yes or No 키워드 : bool  (0) 2023.04.25
C# 안전하지 않은 키워드 : unsafe  (0) 2023.04.25
C# 정적 키워드 : static  (0) 2023.04.25
C# 상속 방지 키워드 : sealed  (0) 2023.04.25

unsafe

뜻 그대로 안전하지 않은 코드를 명시할 때 사용하는 키워드이다.

C#에서 모든 메모리 영역은 가비지 컬렉터에 의해서 관리되는데 관리를 벗어난 영역에 작업을 수행하기 위해서 사용한다.

 

따라서 C#에서 관리하는 기능을 사용하지 않고 직접 관리하는 코드를 사용하겠다는 것을 명시하여 해당 코드를 GC관리로부터 벗어나도록 할 수 있기 때문에 더 자유롭게 메모리 컨트롤이 가능하게 된다. 자유로워진 만큼 메모리 할당과 해제를 모두 직접 구현해야 하며 해당 문제로 에러가 발생하면 메모리 누수, 버퍼 오버플로, 세그먼트 폴트 등 치명적인 결함이 발생하게 된다.

 

발생하는 문제가 치명적인만큼 이를 다루기 위해서 unsafe 키워드를 통해서 반드시 명시된 경우에만 제어권을 얻게 한다. 

기본적으로 unsafe를 사용하게 되면 c# 내부에서는 문제로 인식하고 콘솔에 경고를 보내게 된다.

 

사용처

사용할일이 거의 없는 키워드로 사용하는 상황도 일반적이지 않다.

 

포인터 사용

C#에서는 포인터 사용을 허용하지 않기 때문에 unsafe를 통해서만 직접 사용이 가능하도록 한다.

 

빠른 코드 실행

외부 알고리즘의 경우 빠른 코드 실행이 필요하기도 하는데 이럴 때 unsafe코드를 사용하면 성능을 향상할 수 있다.

 

외부 라이브러리와 상호 작용

일부 외부 라이브러리는 C#의 안전한 기능을 사용할 수 없기도 한데 이때 unsafe코드를 사용하여 외부와 상호 작용이 가능하도록 할 수 있다.

728x90
반응형

'Program Language > C#' 카테고리의 다른 글

C# Yes or No 키워드 : bool  (0) 2023.04.25
C# 변수 동기화 키워드 : volatile  (0) 2023.04.25
C# 정적 키워드 : static  (0) 2023.04.25
C# 상속 방지 키워드 : sealed  (0) 2023.04.25
C# 읽기 전용 키워드 : readonly  (0) 2023.03.30

클래스 멤버를 정의할 때 사용된다.

static으로 정의된 멤버는 객체 인스턴스에 속하는 것이 아닌 클래스 자체에 속하게 된다.

즉, 객체가 인스턴스화되기 전에도 해당 멤버에 접근이 가능한데 클래스 자체에 속하기 때문에 클래스 이름을 통해서 직접 호출이 가능하다.

 

class MyClass
{
	public static int myStaticVariable;
    public static void myStaticMethod(){}
}

class OtherClass
{
	public void SomeFunc()
    {
    	MyClass.myStaticVariable = 10;
    	MyClass.mySaticMethod();
    }
}

 

static 멤버는 모든 인스턴스에 공유되기 때문에 한 객체에서 static 멤버에 대한 수정이 있는 경우 다른 객체에서도 동일한 값을 가지게 된다. 따라서 static 멤버는 클래스의 인스턴스와 관련이 없는 작업을 수행할 때 사용되며 일반적으로 유틸리티 클래스의 메서드나 상수 특정 클래스에서 공통으로 사용하는 변수 등을 정의할 때 static 키워드가 사용된다.

 

주의할 점은 모든 객체에서 공유되므로 서로 다른 스레드에서 동시에 static 멤버를 수정하는 상황이 발생할 수 있는 즉, thread-safe 하지 않기 때문에 멀티스레드 환경에서는 문제가 발생할 수 있다.

 

이러한 특징 때문에 static을 사용할 때는 몇가지 당연한 규칙이 있다.

 

우선 static 클래스의 모든 멤버는 static으로 선언되어야 한다.

클래스가 static이라는 것은 별도의 인스턴스를 생성하지 않아도 해당 클래스를 어디서든 사용이 가능하고 항시 메모리에 올라가 있는 상태라는 뜻이므로 인스턴스가 생성될 때 변수 할당이 이루어지는 일반 변수의 선언은 허용되지 않게 된다.

 

public static class MyStaticClass
{
	// 불가능
    public int number_1;
    // 가능
    public static int number_2;
    static int number_3;
}

 

하지만 반대로 static 클래스가 아니어도 내부의 멤버가 static으로 선언되는 것은 가능하다. 

 

public class MyClass
{
	public static int MyStaticVar = 0;
    public int MyVar = 0;
}

 

정리

static은 처음 선언된 이후 메모리에 상주하기 때문에 언제든 접근 가능하다.

따라서 빈번하게 사용되는 공통적인 변수의 경우 정적으로 선언해서 사용하는 것이 좋을 수 있지만 너무 많은 static을 사용하게 되면 그만큼 상주하는 메모리가 많아지는 것이기 때문에 적절한 사용이 필요하다.

728x90
반응형

+ Recent posts