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

Помимо ответов уже сделано: Это может зависеть от того, что вы пытаетесь сделать, ИМХО. – Samuel

+0

Нет никаких хороших методов для создания потокобезопасного «счетчика» - как и при любом асинхронном программировании, решения должны быть гораздо более информированными, исходя из проблемы, которую вы пытаетесь решить. Счетчик может быть безопасным или не может, в зависимости от вашей ситуации. –

+0

@Samuel обновил мой вопрос – Seenu

ответ

2

Если вы не можете этого избежать, тогда все в порядке. Лучше всего использовать Interlocked class приращение счетчика:

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 
} 

Я оставлю код ниже для случая, когда вам нужно только знать количество в конце

В вашем случае вы можете сохранить 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

Я обновил свой ответ, чтобы выполнить действие каждые 100 тыс. Итераций. –

0

Да, это совершенно нормально до тех пор, как вы держите его thread-safe и синхронизирована в потоках. Вы можете использовать lock для синхронизации. Вы можете больше узнать о безопасности потоков и статических элементах here и here. Вы также можете использовать Interlocked.Increment, чтобы увеличить счетчик поточно-безопасным способом. Узнайте больше о безопасности потоков с помощью оператора increment здесь, в 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#.

См Is the ++ operator thread safe?

атомарных типов в C#?

Посмотреть таблицу What operations are atomic in C#?

Этот ответ показывает, что 32-разрядные интегральные типы атомарный на 32-битных машин, 64 битные целочисленные типы являются атомные на 64-битных машин.

Смежные вопросы