>백엔드 개발 >C#.Net 튜토리얼 >.Net 멀티스레드 프로그래밍의 오용 지점 분석

.Net 멀티스레드 프로그래밍의 오용 지점 분석

怪我咯
怪我咯원래의
2017-04-10 10:59:311965검색

이 글에서는 주로 .Net 멀티스레드 프로그래밍의 오용 지점 분석을 소개합니다. 특정 참조 값이 있는데 아래 편집기로 살펴보겠습니다

1 공유 변수 문제

잘못 작성:

모든 작업이 동일한 변수를 공유할 수 있으므로 출력 결과도 동일할 수 있습니다.

public static void Error()
{
   for(int i=0;i<10;i++)
   {
    Task.Run(() => { Console.WriteLine("{0}", i); });
   }
}

정확한 쓰기:

변수 i를 지역 변수 temp에 할당합니다. 각 작업은 서로 다른 i 값을 사용합니다.

public static void Right()
{
   for (int i = 0; i < 10; i++)
   {
    int temp = i;
    Task.Run(() => { Console.WriteLine("{0}", temp); });
   }
}

2 대기 중인 작업에 필요한 리소스를 정리하지 마세요

잘못된 쓰기:

텍스트 콘텐츠를 비동기적으로 출력하므로 StreamReader를 사용하기 전에 sr 변수가 해당 범위를 벗어나 Dispose 메서드가 호출됩니다.

public static void Error()
{
   using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
   {
    Task.Run(() => { Console.WriteLine("输出:{0}",sr.ReadLine()); });
   }
}

정답:

public static void Right()
{
   using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
   {
    var task = Task.Run(() => { Console.WriteLine("输出:{0}", sr.ReadLine()); });
    task.Wait();
   }
}

3 this, typeof(type), string을 잠그지 마세요

올바른 접근 방식: 객체 유형의 전용 읽기 전용 필드를 정의하고 잠급니다.

4 WaitHandle.WaitAll에 대한 waitHandle 수는 64개 이하여야 합니다.

public static void Error()
{
   ManualResetEvent[] manualEvents = new ManualResetEvent[65];

   try
   {
    for (int i = 0; i < 65; i++)
    {
     var temp = i;
     Task.Run(() =>
     {
      manualEvents[temp] = new ManualResetEvent(false);
      Console.WriteLine("{0}", temp);
      manualEvents[temp].Set();
     });
    }
    WaitHandle.WaitAll(manualEvents);
   }
   catch (Exception ae)
   {
    Console.WriteLine(ae.Message);
   }
}

5 예외를 잡을 수 없습니다

try
{
    var task = Task.Run(() => { throw new Exception("抛异常"); });
    //如果将下面这行代码注掉,则无法抛出异常
    task.Wait();
}
catch(Exception ex)
{
    Console.WriteLine(ex.Message);
}

6 작업 리소스를 해제해야 합니까?

Dispose를 호출하지만 호출은 심각한 실수가 아닙니다.

Task가 특정 상태에 있을 때는 리소스를 해제할 수 없습니다. 그렇지 않으면 오류가 보고됩니다.

public static void CatchException()
{
   try
   {
    Console.WriteLine("开始");
    var task = Task.Run(() =>
    {
     //throw new Exception("抛异常"); 
    });
    //注掉下面这行代码,观察异常结果
    //task.Wait();
    task.Dispose();
    Console.WriteLine("结束");
   }
   catch(Exception ex)
   {
    Console.WriteLine(ex.Message);
   }
}

7 Deadlock Demonstration

tsak1과 task2가 모두 현재 두 번째 잠금을 획득하기 전에 첫 번째 잠금을 성공적으로 획득하면 교착 상태가 발생합니다(tsak1의 경우 요청된 두 번째 잠금은 LockedObj2, task2의 경우 LockedObj1).

private static readonly Object LockedObj1 = new object();
private static readonly Object LockedObj2 = new object();
public static void LockShow()
{
   var task1 = Task.Run(() => 
   {
    lock (LockedObj1)
    {
     Console.WriteLine("get LockedObj1");
     lock (LockedObj2)
     {
      Console.WriteLine("get LockedObj2....");
     }
    }
   });
   var task2 = Task.Run(() =>
   {
    lock (LockedObj2)
    {
     Console.WriteLine("get LockedObj2");
     lock (LockedObj1)
     {
      Console.WriteLine("get LockedObj1....");
     }
    }
   });
}

여러 번 실행하면 다음 두 가지 결과가 나올 수 있습니다. 첫 번째 그림은 교착 상태가 발생하지 않은 상황이고 두 번째 그림은 교착 상태가 발생한 경우입니다. 상황.

8 Thread.Abort 메서드를 호출하지 마세요.

작업은 Abort 메서드를 제공하지 않습니다. 새로운 TPL(.NET 4.0 이후)을 사용하면 일반적으로 작업 취소를 제어하는 ​​데 CancellationToken이 사용됩니다.

9 공유변수가 안전한지 확인

반복적으로 실행하면 아래 그림과 같이 다른 결과를 관찰할 수 있습니다.

아아앙

10프로세서 초과 구독 및 미달 구독

아아앙

위 내용은 .Net 멀티스레드 프로그래밍의 오용 지점 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.