C# 스레드 동기화 대상의 방법 분석

7926 단어
본고의 실례는 C#에서 스레드 동기화 대상의 방법을 설명하였다.여러분에게 참고하도록 공유하다.구체적인 분석은 다음과 같다.
다중 루틴 프로그램을 작성할 때 루틴의 동기화 문제를 피할 수 없습니다.무엇이 라인의 동기화입니까?
예를 들어 만약에 한 회사에서 하나의 변수가 누군가의 T의 임금count=100을 기록한다면 두 명의 주관자 A와 B(즉 업무 라인)가 조금 일찍 이 변수의 값을 가지고 돌아간다. 시간이 지나면 A주임은 T의 임금을 5위안 올리고count 변수를 병존한다. B주임은 T의 임금을 3위안에서 빼고count 변수를 병존한다.자, 원래 T군은 102위안의 월급을 받을 수 있었는데, 지금은 98위안이 되었다.이것이 바로 라인 동기화가 해결해야 할 문제다.
에 있습니다.Net의 일부 대상에서 안의 데이터를 읽는 동시에 데이터를 수정할 수 있는데 이런 대상은 바로'선정 안전'이다.그러나 자신이 작성한 코드 세그먼트에 대해 말하자면, 반드시 스레드 동기화 기술을 사용하여 데이터의 완전성과 정확성을 확보해야 한다.
다음과 같은 몇 가지 규칙이 있습니다.
1. 만약에 한 대상(또는 변수)이 여러 개의 다른 라인에 동시에 접근하지 않는다면 이 대상은 라인을 동기화할 필요가 없다.2. 만약에 여러 개의 라인이 한 대상을 동시에 방문하지만 그들이 방문한 데이터나 방법이 같지 않다면(교차하지 않는다) 이런 상황도 라인을 동기화할 필요가 없다.예를 들어 상례에서 그 회사에 T와 Q 두 사람이 있다면 그들의 임금은 각각 A와 B가 주관한다. 그러면 이 임금의 처리는 라인이 동기화될 필요가 없다.3. 만약에 한 대상이 여러 개의 다른 라인에 동시에 접근할 경우 일반적으로 이 대상에 라인 동기화 코드만 추가하고 다른 라인은 추가 코드를 추가하지 않아도 된다.
C#에서 스레드 동기화에 사용되는 일반적인 클래스는 다음과 같습니다.
1. Mutex클래스(상호 배척기), Monitor클래스, lock방법2, ManualReset Event 클래스, AutoReset Event 클래스(이 두 가지 모두 Event WaitHandle 클래스에서 파생된 것) 3, Reader Writer Lock클래스
같은 종류의 작용은 차이가 많지 않다. 그 중에서 첫 번째 종류의 작용은 특정한 단락의 코드가 실행될 때 독점적인 방식으로 실행되는 것을 보호하는 것이다. 이때 두 번째 라인이 이 대상에 접근하고 싶을 때 중단된다.독점 코드가 실행될 때까지 기다렸어요.마치 한 무리의 사람들이 동시에 공중화장실에 가는 것과 같이 이 방법을 사용하면 문장이 처음에 제기된 문제를 해결할 수 있다. 주관 A가 T군의 월급을 처리하기 전에 T군을 먼저 lock한 다음에 현재의count치를 꺼내서 처리한 후에 T군의 잠금을 해제한다.만약에 주관자 B가 주관자 A가 임금을 처리할 때count치를 꺼내려고 한다면 주관자 B는 A가 처리된 후에야 계속할 수 있다.이 방법을 사용하는 단점 중 하나는 프로그램의 효율을 떨어뜨리는 것이다.원래는 여러 개의 라인 작업이었는데, lock의 문장을 만났을 때, 이 라인들은 줄을 서서 처리하기만 하면 같은 단일 라인 작업이다.
다음은 이 세 가지 방법의 사용을 예를 들어 설명한다.
Tools 클래스가 있다고 가정하면 그 안에 int 변수가 있고 Add와 Delete 방법이 있습니다. 그 중에서 Add 방법은 int 변수의 값을 증가시키고 Delete 방법은 int 변수의 값을 감소시킵니다.

   public class Tools 
  
{
private int count = 100;
public void Add(int n)
{
count+=n;
}
public void Delete(int n)
{
count-=n;
}
}

여러 개의 스레드가 이 코드에 동시에 접근할 때 한 문장이 컴파일러에 의해 여러 개의 명령으로 컴파일되기 때문에 이런 상황이 발생할 수 있다. 그러나 어떤 스레드가Add 방법을 호출할 때 이때의count값은 100이고 n을 추가하려고 할 때 다른 스레드는Delete를 호출했다. 이것은 m을 줄여야 하는데 결과적으로count에 n을 추가한 다음에 원래의count=100의 값을 추가한 경우
m을 빼고 마지막 결과는count가 m를 빼고 n을 붙이지 않았다.Add 방법과 Delete 방법은 동시에 호출될 수 없기 때문에 반드시 스레드 동기화 처리를 해야 한다.간단한 방법은 lock 문을 사용하는 것입니다.

   public class Tools 
  
{
private object abcde = new object();
private int count = 100;
public void Add(int n)
{
lock(abcde)
{
count+=n;
}
}
public void Delete(int n)
{
lock(abcde)
{
count-=n;
}
}
}

그 중에서 abcde는private급의 내부 변수로 어떤 의미도 나타내지 않고 일종의'영패'역할일 뿐이다.
Add 방법 중의 lock (abcde) 방법을 실행할 때, 이 영패는 Add 방법의 손에 있습니다. 만약 두 번째 라인이 있어도 이 영패를 가지려고 한다면, 문이 없고, 기다릴 수밖에 없습니다.첫 번째 lock 문장의 괄호 범위가 끝나면 영패는 방출되고 두 번째 라인의 손에 빠르게 떨어지며 다른 훗날의 사람을 배제한다.
모니터 클래스를 사용하는 방법은 다음과 같습니다.

   public class Tools 
  
{
private object abcde = new object();
private int count = 100;
public void Add(int n)
{
Monitor.Enter(abcde);
count+=n;
Monitor.Exit(abcde);
}
public void Delete(int n)
{
Monitor.Enter(abcde);
count-=n;
Monitor.Exit(abcde);
}
}

모니터의 일반적인 방법: Enter와 Exit는 정적 방법으로 lock 문장의 두 개의 괄호와 같은 역할을 한다.
"Mutex를 사용하면""토큰""객체를 선언하지 않아도 되지만 이를 인스턴스화하여 사용할 수 있습니다."

   public class Tools 
  
{
private Mutex mut = new Mutex();
private int count = 100;
public void Add(int n)
{
mut.WaitOne();
count+=n;
mut.ReleaseMutex();
}
public void Delete(int n)
{
mut.WaitOne();
count-=n;
mut.ReleaseMutex();
}
}

이 중 WaitOne은 미텍스가 풀려날 때까지 기다리는 방법이다.처음에는 Mutex 대상이 방출된 상태였지만 WaitOne 방법을 실행한 후에 포획되었고 Release Mutex 방법이 호출된 후에야 방출되었다.
이 세 가지 방법을 사용하면 모두 주의해야 할 문제가 하나 있다. 바로 독점 코드 구간에서 이상이 발생하면'영패'대상이 풀리지 않고 프로그램이 계속 기다릴 수 있다는 것이다.
그래서 독점 코드 세그먼트에서 이상을 처리해야 합니다.예를 들어 다음과 같은 코드가 잘못되었습니다.

   public void Add(int n) 
  
{
try
{
mut.WaitOne();
count+=n;
//.... N
//....
//.... N
mut.ReleaseMutex();
}
catch
{
Console.Writeline("error.");
}
}

위의 코드가try와catch에서 이상이 발생하면 Mutex는 방출되지 않고, 다음 프로그램은 WaitOne () 줄에서 끊기게 됩니다. 이렇게 바꿔야 합니다.

   public void Add(int n) 
  
{
mut.WaitOne();
try
{
count+=n;
//.... N
//....
//.... N
}
catch
{
Console.Writeline("error.");
}
mut.ReleaseMutex();
}

이제 두 번째:
ManualResetEvent 클래스, AutoResetEvent 클래스
위의 두 종류는 모두 Event WaitHandle 클래스에서 파생된 것이기 때문에 기능과 호출 방법이 매우 비슷하다.
이 두 종류는 어떤 라인의 실행을 차단한 다음에 조건에 부합되는 상황에서 다시 실행하는 데 자주 사용된다.
예를 들어 한 MM에게 꽃을 주고 싶은데 꽃을 보낸 젊은이에게 부탁해서 보냈어요. 그리고 꽃을 받은 후에 바로 전화를 해서 그녀에게 알려주고 싶어요.
문제는 꽃이 언제 MM의 손에 들어갈지 모른다는 것이다. 일찍 치고 늦게 쳐도 좋지 않다. 이럴 때는 Manual Reset Event 대상의 도움을 받을 수 있다.총각에게 꽃을 보내달라고 부탁할 때 Manual Reset Event의 WaitOne 방법으로 기다린다.총각이 꽃을 MM의 손에 넣었을 때, Manual Reset Event의 Set 방법을 다시 사용하면, 당신은 제시간에 전화를 걸 수 있습니다.
또한 Manual Reset Event는 호출자의 실행을 다시 차단하는 데 사용되는 Reset 방법이 하나 더 있다. 이것은 당신이 이 젊은이에게 NMM에 꽃을 보내달라고 부탁하고 제시간에 NMM에게 전화하려고 하는 것과 같다.

   using System; 
  
using System.Threading;
public class TestMain
{
private static ManualResetEvent ent = new ManualResetEvent(false);
public static void Main()
{
Boy sender = new Boy(ent);
Thread th = new Thread(new ThreadStart(sender.SendFlower));
th.Start();
ent.WaitOne(); //
Console.WriteLine(" , :)");
Console.ReadLine();
}
}
public class Boy
{
ManualResetEvent ent;
public Boy(ManualResetEvent e)
{
ent = e;
}
public void SendFlower()
{
Console.WriteLine(" ");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.Write("..");
}
Console.WriteLine(" MM ,boss");
ent.Set(); //
}
}

AutoReset Event 유형은 매번 Set이 끝난 후에 자동으로 Reset을 한다는 뜻이다.실행 프로그램을 다시 막힌 상태로 들어가게 합니다.
AutoResetEvent.Set()은 ManualResetEvent와 같습니다.Set () 이후 즉시 ManualResetEvent.Reset (), 다른 것은 다를 것이 없습니다.
NMM에 꽃을 보내는 예를 들면:

   using System; 
  
using System.Threading;
public class TestMain
{
private static AutoResetEvent ent = new AutoResetEvent(false);
public static void Main()
{
Boy sender = new Boy(ent);
for (int i = 0; i < 3; i++)
{
Thread th = new Thread(new ThreadStart(sender.SendFlower));
th.Start();
ent.WaitOne(); //
Console.WriteLine(" , :) ");
}
Console.ReadLine();
}
}
public class Boy
{
AutoResetEvent ent;
public Boy(AutoResetEvent e)
{
ent = e;
}
public void SendFlower()
{
Console.WriteLine(" ");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.Write("..");
}
Console.WriteLine(" MM ,boss");
ent.Set(); // , ManualResetEvent Set() +Reset()
}
}

이 문서가 C# 프로그램 설계에 도움이 되었으면 합니다.

좋은 웹페이지 즐겨찾기