C\#스 레 드 동기 화 상세 설명
8605 단어 C#스 레 드 동기 화
스 레 드 탱크 의 스 레 드 가 막 힐 때 스 레 드 탱크 는 추가 스 레 드 를 만 들 고 스 레 드 를 만 들 고 소각 하 며 스 레 드 를 예약 하 는 데 상당히 비 싼 메모리 자원 이 필요 합 니 다.또한 많은 개발 자 들 이 자신의 프로그램의 스 레 드 가 유용 한 일 을 하지 않 은 것 을 볼 때 더 많은 스 레 드 를 만 드 는 습관 이 있 습 니 다.신축 가능 하고 민감 한 프로그램 을 구축 하기 위해 앞에서 소개 하 였 습 니 다C\#비동기 프로 그래 밍 상세 설명
그러나 비동기 프로 그래 밍 역시 심각 한 문제 가 존재 합 니 다.만약 에 두 개의 서로 다른 스 레 드 가 같은 변수 와 데 이 터 를 방문 하면 우리 의 비동기 함수 의 실현 방식 에 따라 두 개의 스 레 드 가 같은 데 이 터 를 동시에 방문 할 수 없습니다.이때 우 리 는 스 레 드 동기 화가 필요 합 니 다.여러 스 레 드 가 동시에 공유 데 이 터 를 방문 할 때 스 레 드 동기 화 는 데이터 손상 을 방지 할 수 있 습 니 다.이 개념 을 강조 하 는 이 유 는 스 레 드 동기 화 본질 이 바로 시간 계산 문제 이기 때 문 입 니 다.
비동기 와 동기 화 는 상대 적 인 것 이 고 동기 화 는 순서대로 실행 되 며 하 나 를 실행 하고 다음 을 실행 하려 면 기다 리 고 조율 해 야 한다.이 보 는 서로 독립 하고 어떤 사건 을 기다 리 는 과정 에서 자신의 일 을 계속 하 는 것 이다.이 사건 이 끝 난 후에 일 할 필요 가 없다.스 레 드 는 바로 비동기 적 인 방식 을 실현 하 는 것 이다.비동기 화 는 호출 방법의 메 인 스 레 드 가 다른 스 레 드 의 완성 을 동시에 기다 리 지 않 아 도 메 인 스 레 드 가 다른 일 을 할 수 있 도록 하 는 것 이다.
기본 사용자 모드 와 커 널 모드 구조
기초 개념
기원:코드 에서 사용 할 수 있 는 간단 한 구조
사용자 모드:특수 한 CPU 명령 을 통 해 스 레 드 를 조정 합 니 다.운영 체 제 는 기본 사용자 모드 의 구조 에서 스 레 드 가 차단 되 는 것 을 영원히 감지 하지 못 합 니 다.
커 널 모드:windows 자체 에서 제공 하고 응용 프로그램의 스 레 드 에서 커 널 로 이 루어 진 함 수 를 호출 합 니 다.
사용자 모드 구조
변형 구조
C\#컴 파일 러,JIT 컴 파일 러 와 CPU 는 모두 코드 를 최적화 시 킬 것 이다.그들 은 우리 의 의 도 를 최대한 보류 할 것 이다.그러나 다 중 스 레 드 의 측면 에서 볼 때 우리 의 의 도 는 반드시 보류 되 는 것 이 아니다.다음 과 같은 예 를 들 어 설명 한다.
static void Main(string[] args)
{
Console.WriteLine(" worker 5s ");
var t = new Thread(Worker);
t.Start();
Thread.Sleep(5000);
stop = true;
Console.ReadLine();
}
private static bool stop = false;
private static void Worker(object obj)
{
int x = 0;
while (!stop)
{
x++;
}
Console.WriteLine("worker x={0}",x);
}
컴 파일 러 가 stop 이 false 인 것 을 검사 하면 코드 를 생 성하 여 무한 순환 에 들 어가 고 순환 에서 x 를 계속 증가 하기 때문에 최적화 순환 이 빨리 완성 되 지만 컴 파일 러 는 stop 을 한 번 만 검 측 하고 매번 검 측 하 는 것 이 아니다.
예 2--두 스 레 드 를 동시에 방문 합 니 다.
class test
{
private static int m_flag = 0;
private static int m_value = 0;
public static void Thread1(object obj)
{
m_value = 5;
m_flag = 1;
}
public static void Thread2(object obj)
{
if (m_flag == 1)
Console.WriteLine("m_value = {0}", m_value);
}
// CPU
public void Exec()
{
var thread1 = new Thread(Thread1);
var thread2 = new Thread(Thread2);
thread1.Start();
thread2.Start();
Console.ReadLine();
}
}
프로그램 이 실 행 될 때 컴 파일 러 는 변 수 를 mflag 와 mvalue 는 RAM 에서 CPU 레지스터 를 읽 고 RAM 은 m 를 먼저 전달 합 니 다.value 의 값 0,thread 1 은 값 을 5 로 바 꿉 니 다.그러나 thread 2 는 thread 2 가 여전히 값 이 0 이 라 고 생각 하 는 지 모 릅 니 다.이런 문 제 는 일반적으로 다 핵 CPU 에서 발생 할 확률 이 높 습 니 다.CPU 가 많 을 수록 여러 스 레 드 가 동시에 자원 에 접근 할 확률 이 높 습 니 다.키워드 volatile 은 C\#컴 파 일 러,JTP 컴 파 일 러,CPU 가 실행 하 는 최 적 화 를 금지 하 는 역할 을 합 니 다.변 수 를 사용 하면 CPU 레지스터 에 필드 캐 시 를 허용 하지 않 고 필드 의 읽 기와 쓰기 가 RAM 에서 진행 되도록 합 니 다.
상호 잠 금 구조
System.Threading.Interlocked 클래스 의 모든 방법 은 원자의 읽 기와 쓰기 동작 을 한 번 씩 수행 합 니 다.Interlocked 방법 을 호출 하기 전의 모든 변 수 는 이 Interlocked 방법 이 호출 되 기 전에 실 행 됩 니 다.호출 된 모든 변 수 는 이 호출 후에 읽 습 니 다.
Interlocked 방법 은 주로 INT 32 변수 에 대해 정적 조작 Add,Decrement,Compare,Exchange,CompareChange 등 방법 을 하고 object,Double 등 유형의 매개 변 수 를 받아들인다.
원자 조작:스 레 드 스케줄 러 에 의 해 중단 되 지 않 는 조작 을 말한다.이 동작 은 시작 하면 끝 날 때 까지 실 행 됩 니 다.중간 에 context switch(다른 스 레 드 로 전환)가 없습니다.
코드 데모:
설명:Interlocked 방법 을 통 해 몇 개의 웹 서버 를 비동기 로 조회 하고 데 이 터 를 동시에 되 돌려 주 며 결 과 는 한 번 만 실 행 됩 니 다.
//
enum CoordinationStatus
{
Cancel,
Timeout,
AllDone
}
class AsyncCoordinator
{
//AllBegun JustEnded
private int _mOpCount = 1;
//0=false,1=true
private int _mStatusReported = 0;
private Action<CoordinationStatus> _mCallback;
private Timer _mTimer;
//
public void AboutToBegin(int opsToAdd = 1)
{
Interlocked.Add(ref _mOpCount, opsToAdd);
}
//
public void JustEnded()
{
if (Interlocked.Decrement(ref _mOpCount) == 0)
{
ReportStatus(CoordinationStatus.AllDone);
}
}
//
public void AllBegin(Action<CoordinationStatus> callback, int timeout = Timeout.Infinite)
{
_mCallback = callback;
if (timeout != Timeout.Infinite)
{
_mTimer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
JustEnded();
}
}
private void TimeExpired(object o)
{
ReportStatus(CoordinationStatus.Timeout);
}
public void Cancel()
{
ReportStatus(CoordinationStatus.Cancel);
}
private void ReportStatus(CoordinationStatus status)
{
// , , ,
if (Interlocked.Exchange(ref _mStatusReported, 1) == 0)
{
_mCallback(status);
}
}
}
class MultiWebRequest
{
//
private AsyncCoordinator _mac = new AsyncCoordinator();
protected Dictionary<string,object> _mServers = new Dictionary<string, object>
{
{"http://www.baidu.com",null},{"http://www.Microsoft.com",null},{"http://www.cctv.com",null},
{"http://www.souhu.com",null},{"http://www.sina.com",null},{"http://www.tencent.com",null},
{"http://www.youku.com",null}
};
private Stopwatch sp;
public MultiWebRequest(int timeout = Timeout.Infinite)
{
sp = new Stopwatch();
sp.Start();
//
var httpclient = new HttpClient();
foreach (var server in _mServers.Keys)
{
_mac.AboutToBegin(1);
httpclient.GetByteArrayAsync(server).ContinueWith(task => ComputeResult(server, task));
}
_mac.AllBegin(AllDone,timeout);
Console.WriteLine("");
}
private void ComputeResult(string server, Task<Byte[]> task)
{
object result;
if (task.Exception != null)
{
result = task.Exception.InnerException;
}
else
{
// IO
result = task.Result.Length;
}
//
_mServers[server] = result;
_mac.JustEnded();
}
public void Cancel()
{
_mac.Cancel();
}
private void AllDone(CoordinationStatus status)
{
sp.Stop();
Console.WriteLine(" {0}",sp.Elapsed);
switch (status)
{
case CoordinationStatus.Cancel:
Console.WriteLine(" ");
break;
case CoordinationStatus.AllDone:
Console.WriteLine(" , ");
foreach (var server in _mServers)
{
Console.WriteLine("{0}",server.Key);
object result = server.Value;
if (result is Exception)
{
Console.WriteLine(" {0}",result.GetType().Name);
}
else
{
Console.WriteLine(" :{0}",result);
}
}
break;
case CoordinationStatus.Timeout:
Console.WriteLine(" ");
break;
default:
throw new ArgumentOutOfRangeException("status", status, null);
}
}
}
이상 의 코드 를 참고 하 시 는 것 을 권장 합 니 다.저 는 서버 에 접근 할 때 도 이 모델 을 자주 참고 합 니 다.간단 한 자전거 자물쇠
class SomeResource
{
private SimpleSpinLock s1 = new SimpleSpinLock();
public void AccessResource()
{
s1.Enter();
//
s1.Leave();
}
}
class SimpleSpinLock
{
private int _mResourceInUse;
public void Enter()
{
while (true)
{
if(Interlocked.Exchange(ref _mResourceInUse,1)==0)
return;
}
}
public void Leave()
{
Volatile.Write(ref _mResourceInUse,1);
}
}
이것 은 바로 스 레 드 동기 자물쇠 의 간단 한 실현 이다.이런 자물쇠 의 가장 큰 문 제 는 경쟁 이 존재 하 는 상황 에서 스 레 드 의'자전'을 초래 할 수 있다 는 것 이다.이것 은 CPU 의 소중 한 시간 을 낭비 하고 CPU 를 조직 하여 더 많은 일 을 할 수 있 기 때문에 이런 자전 자 물 쇠 는 매우 빠 른 코드 를 보호 하 는 데 사용 해 야 한다.이상 은 본 고의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.또한 저 희 를 많이 지지 해 주시 기 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
WebView2를 Visual Studio 2017 Express에서 사용할 수 있을 때까지Evergreen .Net Framework SDK 4.8 VisualStudio2017에서 NuGet을 사용하기 때문에 패키지 관리 방법을 packages.config 대신 PackageReference를 사용해야...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.