Параллельно: как правильно синхронизировать - PullRequest
0 голосов
/ 17 октября 2010

У меня следующий довольно простой сценарий: некоторые данные необходимо записать в БД (довольно большая коллекция), которая может быть разбита на разделы.Но у меня есть две проблемы:

  1. Простая: хотелось бы иметь возможность печатать индикатор выполнения, чтобы узнать, сколько записей было вставлено так далеко от времени довремя (вроде общего счетчика между потоками).

  2. Сложнее: каждая запись должна сопровождаться отметкой времени.Временные метки имеют начальное время и интервал.Временная метка, к сожалению, не является частью записи, но в последовательном программировании ее можно просто рассчитать, увеличив текущую на определенный интервал.

Пока что возникает вопрос: как реализоватьвышеуказанные ограничения правильно?Можно ли каким-то образом отделить тело цикла от кода, который выполняется при продвижении итерации (++i или newTimeStamp = oldTimeStamp.AddSeconds(...)), чтобы код такого типа всегда выполнялся в одном потоке, в отличие от тела цикла, которое будетраспараллеливать? Если возможно, фрагмент кода будет очень полезен, хотя я буду рад получить даже любые указатели / имена / ключевые слова. Спасибо.

Ответы [ 2 ]

1 голос
/ 17 октября 2010

Для первой части вы можете использовать мьютекс (lock оператор ) или даже один из Interlocked методов .

int counter = 0;
object counterLock = new object();
void IncreaseCounter()
{
    lock (counterLock)
        counter++;
}

int GetCounter()
{
    lock (counterLock)
        return counter;
}

или

int counter = 0;
void IncreaseCounter()
{
    Interlocked.Increment(ref counter);
}

int GetCounter()
{
    return Interlocked.Read(ref counter);
}

Для использования из графического интерфейса пользователя вы можете распространить изменения своего счетчика на соответствующий DependencyProperty (если вы используете WPF).

Для второй части, почему не может быть отметка временирассчитываться для каждой записи индивидуально, чтобы вам не приходилось делить что-либо между потоками?Может быть, я не правильно понял ваш вопрос, не могли бы вы описать проблему №2 более подробно?

0 голосов
/ 17 октября 2010

Вам не нужно делать это в одном потоке, вам просто нужно убедиться, что это делает только один поток:

public class Synchoniser {

  private int _progress;
  private int _total;
  private int _counter;
  pricate object _sync;

  public Synchroniser(int total, int counterSeed) {
    _progress = 0;
    _total = total;
    _counter = counterSeed;
    _sync = new Object();
  }

  public void AdvanceProgress() {
    lock (_sync) {
      _progress++;
    }
  }

  public int GetProgress() {
    lock (_sync) {
      return 100 * _progress / _total;
    }
  }

  public int GetNextCounter() {
    lock (_sync) {
      _counter++;
      return _counter;
    }
  }

}

Создайте отдельный экземпляр класса и передайте его каждому потоку. Теперь каждый из них может продвигать прогресс и получить следующее значение счетчика.

...