'개발언어/C#'에 해당되는 글 5건

  1. 2021.06.20 Thread와 Task
  2. 2019.11.29 CancellationTokenSource 과 CancellationToken
  3. 2019.11.28 ThreadStatic 과 ThreadLocal
  4. 2019.09.05 알아두면 어쩌다 쓸것같은 Attribute들-1
  5. 2019.08.11 async, await란

2021. 6. 20. 22:55 개발언어/C#

Thread와 Task

반응형

우선 Thread에 대해서는 보통 잘 알것이다.

 

Process에 속하며 같은 Process에 속한 Thread 끼리는 data, code, heap 영역을 공유한다.

 

그렇다면 C#에서 async, await를 할 때 언급되는 Task와 Thread는 어떠한 차이가 있는것일까?

 

우선 MSDN 문서 기준으로  Task class는 비동기 작업을 나타낸다고 되어 있다.

 

즉 Thread의 경우 Process에서의 "실행 흐름"을 나타낸다면

 

Task는 "비동기적으로 실행되는 단일 작업" 을 의미한다.

 

Task는 C# .NET Framework4에서 처음 도입된 TAP패턴의 구성요소이다.

 

Task는 C#이 관리하는 Thread pool을 통해서 실행, 관리되며 Status 속성, IsCancled 등을 통해

 

외부에서 해당 Task의 작업 현황을 알 수 있다.

 

C#에서 Task를 생성 및 실행하는 방법은 여러가지가 존재하며 

 

개인적으로 자주 사용하는 방법은 Task.Factory.StartNew / Task.Run 이 두가지 방법이다.

 

Task를 생성, 실행한 후 해당 Task에 대해서 await를 앞에 적어주면 Task가 작업을 완료할 때까지 대기하게 된다.

 

이 때 내부적으로 일어나는 일은 More Effective C#에 자세히 나와있으니 참고할 것.

 

아 그리고 Task가 비동기적으로 실행되는 작업 단위라고 했지만 Task의 생성 및 실행과 동시에 작업이 완료될 수 있다.

 

개인적으론 Multi Tasking / MultiThreading 두가지 모두 Server에서 유효하지만

 

C#이 관리하는 Thread Pool 을 통한 Task단위로 작업을 실행하는 것이 개발자의 실수를 좀더 줄여주지 않을까 싶다.

 -> 단, Task는 현자의 돌이 아니니 사용할 때 개념을 확실히 잡고 사용해야 한다.

반응형

'개발언어 > C#' 카테고리의 다른 글

CancellationTokenSource 과 CancellationToken  (0) 2019.11.29
ThreadStatic 과 ThreadLocal  (0) 2019.11.28
알아두면 어쩌다 쓸것같은 Attribute들-1  (0) 2019.09.05
async, await란  (0) 2019.08.11
Posted by Sweetmeats_boy
반응형

출처 : MSDN : https://docs.microsoft.com/ko-kr/dotnet/standard/threading/cancellation-in-managed-threads

 

관리되는 스레드의 취소

관리되는 스레드의 취소Cancellation in Managed Threads 이 문서의 내용 --> .NET Framework 4부터 .NET Framework에서는 비동기 또는 장기 실행 비동기 작업의 협조적 취소를 위한 통합 모델을 사용합니다.Starting with the .NET Framework 4, the .NET Framework uses a unified model for cooperative cancellation of asynchron

docs.microsoft.com

우리가 비동기 함수를 호출할 때 가령 socket의 accept를 비동기로 호출한 후

서버 가동을 중지할 때 해당 Accept를 중지하는 경우 등등 해당 비동기 함수에 대하여

작업을 취소해야하는 경우가 있을 수 있다.

 

이런 경우 해당 함수에 대하여 직접적인 접근을 할 수도 있겠지만

단순히 중지를 알림으로써 해결할 수도 있을 것이다.

이와 관련하여 사용할 수 있는것이 CancellationTokenSource와 CancellationToken이다.

 

이해한 바에 따르면 우선 Token의 경우 구조체이기 때문에 값복사가 이루어진다.

이러한 토큰은 TokenSource의 인스턴스가 제공하는 CancellationTokenSource.Token의 반환값을 사용하며,

이 token을 각각의 "취소요청을 수신할 스레드"에 전달한다.

물론 위의 스레드, 작업(Task)의 경우 token이 최소된 경우 처리할 로직을 구현해야한다.

더불어 만약 TokenSource가 Token외 별도의 리소스를 지닌 상태라면

해당 리소스에 관한 처리도 Dispose에서 처리해줘야 한다.

 

MSDN에서 제공한 소스코드 예제를 보자.

using System;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Create the token source.
      CancellationTokenSource cts = new CancellationTokenSource();

      // Pass the token to the cancelable operation.
      ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);
      Thread.Sleep(2500);

      // Request cancellation.
      cts.Cancel();
      Console.WriteLine("Cancellation set in token source...");
      Thread.Sleep(2500);
      // Cancellation should have happened, so call Dispose.
      cts.Dispose();
   }

   // Thread 2: The listener
   static void DoSomeWork(object obj)
   {
      CancellationToken token = (CancellationToken)obj;

      for (int i = 0; i < 100000; i++) {
         if (token.IsCancellationRequested)
         {
            Console.WriteLine("In iteration {0}, cancellation has been requested...",
                              i + 1);
            // Perform cleanup if necessary.
            //...
            // Terminate the operation.
            break;
         }
         // Simulate some work.
         Thread.SpinWait(500000);
      }
   }
}
// The example displays output like the following:
//       Cancellation set in token source...
//       In iteration 1430, cancellation has been requested...

위에서 보이듯이 TokenSource인 cst가 cancel함수를 호출한 경우

DoSomeWork의 인자로 들어간 token의 IsCancellationRequest가 바뀐다.

이 때 token이 IsCancellationRequested가 한번 true로 변경될 시 다시 false로 바꿀 수 없다.

 

또 다른 활용법으로는 취소 요청이 호출된 순간에 처리할 작업을 지정하는것도 가능하다.

using System;
using System.Threading;

class CancelableObject
{
   public string id;
   
   public CancelableObject(string id)
   {
      this.id = id;
   }
   
   public void Cancel() 
   { 
      Console.WriteLine("Object {0} Cancel callback", id);
      // Perform object cancellation here.
   }
}

public class Example
{
   public static void Main()
   {
      CancellationTokenSource cts = new CancellationTokenSource();
      CancellationToken token = cts.Token;

      // User defined Class with its own method for cancellation
      var obj1 = new CancelableObject("1");
      var obj2 = new CancelableObject("2");
      var obj3 = new CancelableObject("3");

      // Register the object's cancel method with the token's
      // cancellation request.
      token.Register(() => obj1.Cancel());
      token.Register(() => obj2.Cancel());
      token.Register(() => obj3.Cancel());

      // Request cancellation on the token.
      cts.Cancel();
      // Call Dispose when we're done with the CancellationTokenSource.
      cts.Dispose();
   }
}
// The example displays the following output:
//       Object 3 Cancel callback
//       Object 2 Cancel callback
//       Object 1 Cancel callback

위 코드에서 보이듯이 해당 token에 Register 함수를 통해 token에 취소 요청이 올 경우 처리할 작업을 등록할 수 있다.

 

이 외에 Exception 을 활용한 방법도 존재하며 이방법에 대해서는 아래의 링크를 참고하면 된다.

https://docs.microsoft.com/ko-kr/dotnet/standard/parallel-programming/task-cancellation

 

작업 취소

작업 취소Task Cancellation 이 문서의 내용 --> System.Threading.Tasks.Task 및 System.Threading.Tasks.Task 클래스는 .NET Framework에서 취소 토큰을 사용하는 방법으로 취소 기능을 지원합니다. The System.Threading.Tasks.Task and System.Threading.Tasks.Task classes support cancellation through the use

docs.microsoft.com

 

 

반응형

'개발언어 > C#' 카테고리의 다른 글

Thread와 Task  (0) 2021.06.20
ThreadStatic 과 ThreadLocal  (0) 2019.11.28
알아두면 어쩌다 쓸것같은 Attribute들-1  (0) 2019.09.05
async, await란  (0) 2019.08.11
Posted by Sweetmeats_boy
반응형

ThreadStatic과 ThreadLocal의 역할은 각 스레드가 고유한 변수를 지니게 만드는 것이다.

 

다만 약간의 차이가 있으며 그 사항은 아래와 같다.

1. ThreadStatic의 경우 전역  변수에 한해서 사용 가능하다.

2. ThreadStatic에 초기값을 설정할 시 모든 스레드가 기본 초기값으로만 초기화가 된다.

 

[ThreadStatic]
public static int staticVal = 10;


public void int Main()
{
	staticVal = 25;
    
    Thread t1 = new Thread(()=>{
    	Console.WriteLine(staticVal);
    });
    staticVal = 50;
    Thread t2 = new Thread(()=>{
    	Console.WriteLine(staticVal);
    });
    staticVal = 100;
    Thread t3 = new Thread(()=>{
    	Console.WriteLine(staticVal);
    });
}

대충 위와 같은 코드가 존재할 시 각 출력함수들은 모두 10을 출력하게 된다.

이유는 Main함수가 속한 Thread에서의 staticValue값과 t1, t2, t3에서의 staticValue 값은 별개이기 때문이다.

 

ThreadLocal의 경우 ThreadStatic과 같이 각 스레드에 속한 고유 변수를 만들 때 사용한다.

다만 차이점으로는 ThreadStatic과 달리 초기값지정이 가능하다는 것과 전역변수일 필요가 없다는 점이다.

 

public void Main()
{
	ThreadLocal<int> tId = new ThreadLocal<int>(()=>{
    	return Thread.CurrentThread.ManagedThreadId;
    });
    
    Thread t1 = new Thread(()=>{
    	Console.WriteLine("tid : "+tId);
    });
    Thread t2 = new Thread(()=>{
    	Console.WriteLine("tid : "+tId);
    });
    Thread t3 = new Thread(()=>{
    	Console.WriteLine("tid : "+tId);
    });
}

대충 위와 같은 코드의 경우 t1~t3은 각각 생성된 Thread의 id 값으로 초기화가 된다.

 

간단하게 게임등에서 사용하는 경우로는 random과 관련된 로직이 있다.

단순 random의 경우 단순 시간정보로 시드를 대입하면 모든 스레드에서 동일한 값이 추출되지만

이 시드값에 위의 코드처럼 각 스레드의 고유한 값을 조합한다면 모두 다른 랜덤값이 추출될 것이다.

 

다만 ThreadLocal의 경우 .Net 4.0 부터 추가됐기 때문에 버전을 고려해서 사용해야 한다.

ThreadLocal<Random> tRand = new ThreadLocal(()=>{
	return new Random();
});

ThreadLocal<Random> tRand2 = new ThreadLocal(()=>{
	return new Random(Thread.CurrentThreadId + something);
});

위 코드 둘다 각 스레드 고유의 랜덤을 생성해서 반환하지만 

tRand의 경우 만약 다른 두 스레드의 초기화 시간이 미미한 차이라면 같은 Random분포를 지니게 된다.

tRand2의 경우처럼 스레드 개별 정보를 추가해서 구분해준다면 모든 스레드의 Random객체는 다른 분포를 지니게 될 것이다.

 

반응형

'개발언어 > C#' 카테고리의 다른 글

Thread와 Task  (0) 2021.06.20
CancellationTokenSource 과 CancellationToken  (0) 2019.11.29
알아두면 어쩌다 쓸것같은 Attribute들-1  (0) 2019.09.05
async, await란  (0) 2019.08.11
Posted by Sweetmeats_boy
반응형

1. DebuggetDisplayAttribute

[DebuggerDisplay("Count = {count}")]
class MyHashtable
{
    public int count = 4;
}

이 Attribute의 경우 toString() 과 같은 역할을 한다. 즉, MyHashtable 객체에 toString() 시 Count="x" 로 출력됨.

 

 

2. Conditional Attribute

[Conditional("DEBUG")]
static void Method2() 
{
	Console.WriteLine("called");
}

 

이 Attribute의 경우 C에서의 #if DEBUG 와 같이 현재 실행모드가 Debug 인 경우에 대해서 사용 할 수 있다.

conditional Attribute에 지정한 모드인 경우에 해당 methid등이 구현되는 방식이며

만일 다른 모드 일 시 해당 코드는 컴파일 단계에서 무시된다.

주의 할 점은 우선 return 값이 void 여야 한다는 점, 코드 양이 많아진 후에 해당 함수 호출과 관련된 버그가 발생할 시

 분명 함수를 호출했음에도 관련 로직 실행이 안되는 등 찾기 어렵다는 점이다.

반응형

'개발언어 > C#' 카테고리의 다른 글

Thread와 Task  (0) 2021.06.20
CancellationTokenSource 과 CancellationToken  (0) 2019.11.29
ThreadStatic 과 ThreadLocal  (0) 2019.11.28
async, await란  (0) 2019.08.11
Posted by Sweetmeats_boy

2019. 8. 11. 16:27 개발언어/C#

async, await란

반응형

출처 : http://www.csharpstudy.com/CSharp/CSharp-async-await.aspx

 

C# await - C# 프로그래밍 배우기 (Learn C# Programming)

C# 5.0 : async / await 키워드 C# 5.0부터 새로운 C# 키워드로 async와 await가 추가되었다. 이 키워드들은 기존의 비동기 프로그래밍 (asynchronous programming)을 보다 손쉽게 지원하기 위해 C# 5.0에 추가된 중요한 기능이다. C# async는 컴파일러에게 해당 메서드가 await를 가지고 있음을 알려주는 역활을 한다. async라고 표시된 메서드는 await를 1개 이상 가질 수 있는데, 하나도 없는

www.csharpstudy.com

async / await 는 C#  5.0부터 추가된 새로운 키워드이다.

이 키워드들은 기존의 비동기 프로그래밍을 좀 더 쉽게 작업할 수 있게 도와준다.

 

우선 Async 키워드는 해당 메소드가 Await을 지니고 있음을 컴파일러에게 알려주는 역할을 한다.

만약 async 키워드를 지닌 메소드가 내부에 await 를 단 한개도 지니고 있지 않은 경우에도 컴파일은 되지만 

warning을 발생시킨다.

 

일반적으로 Task, Task<T> 객체와 같이 사용되며 Task 의외의 클래스에도 사용이 가능하다.

[awaitable 클래스, GetAwaiter() 메소드를 지닌 클래스라면 이 역시 사용 가능하다.]

 

await는 Task, 혹은 awaitable 클래스의 객체가 완료될때까지 대기한다.

await는 기다리는 Task가 끝날때까지 기다렸다가 완료 후, await 바로 다음 실행문부터 실행을 계속한다.

 

await는 해당 키워드가 사용된 Task가 완료된 후의 로직을

Task가 시작한 Thread와 같은 Thread내에서 실행하는것을 보장한다.

 

비동기 메소드는 여러 return값을 가질 수 있다.

Task<T> / Task / void 를 가질 수 있는데 Task<T>의 경우 return 값이 T형이며 단순 Task의 경우 return 값이 없다.

void 의 경우 비동기 메소드가 이벤트 핸들러로 사용되는 경우이다.

[아마도 UI 이벤트 핸들러로 사용할 때???]

void 예제 코드: 

private async void Button_Click(object obj, EventArgs e)

{

    Task<int> accessTheWebTask = AccessTheWebAsync();

    string result = await accessTheWebTask;

    tbxAverageAge.Text = result;

}

 

async await 의 실행흐름

우선 비동기 메소드를 호출한다.

해당 메소드를 호출하면 우선 호출한 메소드(이하 호출자)의 Thread가 Cpu를 할당 받은 후 관련 로직이 실행된다.

해당 로직은 await를 만나기전까지 수행되며 await를 만나면 해당 await작업이 종료될때까지 대기하게 된다.

해당 await 작업은 호출자가 cpu를 할당받을 때마다 작업을 수행하며, await 작업이 종료되면 나머지 코드들을 수행한다.

즉 await 키워드는 호출자의 Thread 내에서 수행되며 별도의 Thread를 추가 생성하지 않습니다.

 

 

반응형

'개발언어 > C#' 카테고리의 다른 글

Thread와 Task  (0) 2021.06.20
CancellationTokenSource 과 CancellationToken  (0) 2019.11.29
ThreadStatic 과 ThreadLocal  (0) 2019.11.28
알아두면 어쩌다 쓸것같은 Attribute들-1  (0) 2019.09.05
Posted by Sweetmeats_boy
이전버튼 1 이전버튼

블로그 이미지
Sweetmeats_boy

태그목록

Yesterday
Today
Total

달력

 « |  » 2024.9
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함