开发者

Design Pattern for multithreaded task overall progress report

开发者 https://www.devze.com 2023-04-12 09:33 出处:网络
I have a library with an IJobMaker entity that creates a certain amount of IJob objects to be run on threads of their own managed by the user.

I have a library with an IJobMaker entity that creates a certain amount of IJob objects to be run on threads of their own managed by the user. To track each IJob's progress I implement the observer pattern with an IProgressObserver within every job. The difficulty arises when I wish to report on OVERALL progress.

The ideal for me would be to have IProgressO开发者_运维技巧verserver.ReportProgress(float jobProgress, float overallProgress that reports both job and overall progress.IJobMaker can be aware of each job's portion of the overall work and somehow gather everyone's reports.

Two main questions arise:

  1. Synchronization mechanism? Keeping a mutex inside IJobMaker for example could harm performance because IProgressOverserver.ReportProgress gets called a lot and a mutex could incur a context switch and what not. InterlockedIncrement looks like a good option but since there's no such function for floating point, I would be forced to report progress by integer increments. (I'd like to stay away from c++0x features or Boost)

  2. Design pattern? IJob's progress is reported from within its deepest algorithms. I need every such a report to both communicate with a central entity for overall progress calculation and call the IProgressObserver.ReportProgress method which resides in IJob.


A couple of suggestions on the threading front:

  1. Don't report every tiniest bit of progress. Only report to the main thread once a certain predefined amount of progress has been made, or a certain predefined amount of time has passed, or the sub-job has finished. This could greatly cut down on the amount of synchronization.
  2. If you implement #1, a mutex might work pretty well.
  3. If the mutex turns out to be too expensive, you could report progress using an atomic integer variable: simply scale the values from "no progress" to "all done" to 0...INT_MAX.

As far as designing the API, it shouldn't be too difficult to come up with something sensible. My general advice would be to not overengineer it.


First of all, it's quite bad practice to use floats in such cases. Use an integer.

There is another suggestion. You can use segmentation - synchronise only few threads by one mutex/atomic (one segment). And then collect total among all segments.

Also, there is good place to start looking around highly parallel algorithms: http://www.1024cores.net/home/lock-free-algorithms

UDPATE There is example of problems with the float

#include <iostream>
using namespace std;
int main() {
    float f = 0;
    for(int i=0; i<100000-98; ++i)
    {
        f += 0.00001;
    }
    cout << f << endl;
}

So, if you have 100 jobs with 1000 steps each, you will have 1.0 result in 98 earlier than you could expect.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号