2013-12-17 3 views
0

C# .NET 프로그램의 모든 스레드에서 업데이트 할 수있는 정적 변수를 카운터로 사용하는 것이 좋습니다.
샘플 코드 :정적 변수 및 다중 스레딩

public class SomeTask 
{ 
static int count = 0; 
public void Process() 
{ 

    while(true) 
    { 
     //some repeated task 
     count++; 
     if(count>100000) 
     { 
      count=0; 
      break; 
     } 
    } 
} 
} 

public class WorkerRole : RoleEntryPoint 
{ 
    public override void Run() 
    { 
    while(true) 
    { 

     for (int i = 0; i < maxTasks; i++) 
     { 
      this.Tasks[i] = Task.Factory.StartNew(() => (new SomeTask()).Process()); 
     } 
     Task.WaitAll(this.Tasks); 

     //every 100000 in counter needs some updates at program level 
    } 
} 
} 
+2

: 이것은 당신이 뭘 하려는지에 달려 있습니다, IMHO. – Samuel

+0

스레드 안전 "카운터"를 사용하는 것은 바람직하지 않습니다. 모든 비동기 프로그래밍에서와 마찬가지로 해결하려는 문제를 기반으로 의사 결정에 훨씬 많은 정보를 제공해야합니다. 카운터는 귀하의 상황에 따라 안전 할 수도 있고 그렇지 않을 수도 있습니다. –

+0

@Samuel이 내 질문을 업데이트했습니다. – Seenu

답변

2

당신이 그것을 피할 수 없다면 괜찮습니다. 당신이를 유지할 수 만 귀하의 경우에는 마지막

의 수를 알아야 할 때이 경우에 아래의 코드를 떠날거야

if (Interlocked.Increment(ref counter) % 100000 == 0) { 
    // Do something every hundred thousand times 
    // Use "== 1" if you also want to do it on the first iteration 
} 

: 그것은 Interlocked class 증가를 카운터를 사용하는 것이 가장 좋습니다 인스턴스 필드로 count (즉, 비 정적), 공공 게터를 추가하고 모든 작업을 완료 한 후 모든 카운터를 요약 : 이미 만들어진 답변 옆에

public class SomeTask 
{ 
    int count = 0; 
    public int Count { get { return count; } } 

    public void Process() 
    { 

     while(true) 
     { 
      //some repeated task 
      count++; 

      if (something) 
       break; 
     } 
    }   
} 

var someTasks = new List<SomeTask>(); 
for (int i = 0; i < maxTasks; i++) 
{ 
    var someTask = new SomeTask(); 
    someTasks.Add(someTask); 
    this.Tasks[i] = Task.Factory.StartNew(() => someTask.Process()); 
} 
Task.WaitAll(this.Tasks); 

// Your total count 
var total = someTasks.Sum(t => t.Counter); 
+0

당신의 대답은 논리적으로 정확합니다. 이전에 제 질문에 정확한 요구 사항을 제시하지 못했습니다. 지금 나는 질문을 업데이트했다. – Seenu

+0

100k 반복마다 작업을 수행하기 위해 내 대답을 업데이트했습니다. –

0

, 그것은 완벽하게 모든 권리만큼 당신이 thread-safe을 유지하고 스레드 원 공급기과 같다. 동기화에 lock을 사용할 수 있습니다. 스레드 안전성과 정적 멤버 herehere에 대해 자세히 읽을 수 있습니다. Interlocked.Increment을 사용하여 스레드로부터 안전한 방식으로 카운터를 증가시킬 수 있습니다. 여기에서 increament 연산자를 사용하여 스레드 안전성에 대해 자세히 알아보십시오. Eric Lippert answer.

class Account 
{ 
    int count; 
    private Object thisLock = new Object(); 

    public void Add(decimal amount) 
    { 
     //your code 
     lock (thisLock) 
     { 
      count = count + 1; 
     } 
    } 
} 
+0

카운트가 증가하는 경우에만 잠금이 필요 없다고 말하는 것이 맞을까요? 아니면이 작업에서도 '예외'가 발생할 수 있습니까? – tjheslin1

+1

이 시나리오에서는 잠금을 사용하지 말 것을 권장합니다. 잠금은 비용이 많이 들고 카운터를 늘리기 위해 잠금을 수행하면 많은 성능을 저하시킬 수 있습니다. – Euphoric

+0

@Euphoric 내 생각은 정확하게. – tjheslin1

2

예 그건 좋은 방법 하지만 당신은 원자 유형를 사용하십시오. 카운터 증가 연산이 원자 연산과 반대로 스레드 안전 코드를 사용하여 구현되면 성능 문제가 발생할 수 있습니다.

카운터를 구현하려면 ++--을 사용해야합니다. 이들은 일반적으로 C#의 기본 유형에 대해 스레드로부터 안전하지 않습니다.

는 C#에서 Is the ++ operator thread safe?

원자 유형을 참조하십시오?

이 답변은 32 비트 정수 타입은 32 비트 컴퓨터, 64 비트 정수 타입은 64 개 비트 시스템에있는 원자의 원자임을 시사 기준을 What operations are atomic in C#?

참조.