views:

33

answers:

2

I have a following fairly simple scenario: Some data needs to be written into a DB (pretty big collection) that can be partitioned. But I have two problems:

  1. Easy one: would like to have an option to print the progress bar, so that would like to know how many records have been inserted so far from time to time (kinda shared counter among the threads).

  2. Harder one: each record needs to be accompanied by a timestamp. The timestamps have a starting time and an interval. The timestamp is unfortunately not a part of the record but in sequential programming can be simply calculating by incrementing the current one by a particular interval.

So far, the question is: how to implement the above constraints properly? Is it somehow possible to separate the loop body from the code that is executing when promoting an iteration (++i or newTimeStamp = oldTimeStamp.AddSeconds(...), so that that kind of code will be always executed on a single thread, contrary to the loop body that will be parallelized? If possible, the code snippet will be very helpful, though I'll be happy to get even any pointers/names/keywords. Thanks.

A: 

For the part 1, you can use either a mutex (lock statement), or even just one of Interlocked methods.

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

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

or

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

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

For using from GUI, you can propagate your counter changes to an appropriate DependencyProperty (if you are using WPF).

For the second part, why cannot the timestamp be calculated for each record individually, so that you don't need to share anything between threads? Maybe I did't understand your question properly, could you please describe the problem #2 in more detail?

Vlad
Thanks, for the prob N1 Interlocked.Increment is just what I need. The second prob is that I can (in general) to create the records' array with the timestamps already, but it's big and (if possible) I would like to examine the timestamp-on-the-flow generation. The generation rule is very simple: just advance the timestamp for a particular interval for every subsequent record.
BreakPhreak
@BreakPhreak: For the 2nd problem, I still don't get it; maybe you can post the code which does what you'd like to have in a single-threaded case?
Vlad
record.setTimestamp(timestamp = timestamp.AddSeconds(1)); but actually thanks - I've just came up with the formula solution for the second part.
BreakPhreak
@BreakPhreak: Perhaps you could just use [`DateTime.Now()`](http://msdn.microsoft.com/en-us/library/system.datetime.now.aspx).
Vlad
A: 

You don't need to do that in a single thread, you just have to make sure that only one thread at a time does it:

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;
    }
  }

}

Create a single instance of the class, and give it to each thread. Now they can each advance the progress and get the next counter value.

Guffa
all great, but the prob N2 still persists: I can add a timestamp field to your Synchronizer and fetch it every time I am advancing progress. Is that what you mean or there is a more optimal way to treat the problem?
BreakPhreak