이 글에서는 주로 .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 중국어 웹사이트의 기타 관련 기사를 참조하세요!