4
\$\begingroup\$

I have two threads, called Fun and Boring. Each thread takes the same read-only data and runs some calculations over it and returns a [0.0, 1.0] result.

In the current setup, Fun acts as the main thread. It gathers, prepares, and stores the data in a global variable; a memory barrier is used. It then signals (via an event) the Boring thread that there is data to work on. Fun and Boring now both operate on the data.

Here is code which illustrates the set up:

struct Data
{
    void*   someData;
} g_data;

struct Results
{
    float fun;
    float boring;
} g_results;

Fun::Run()
{
    g_data = somePointer;   // Prepare data
    // *memory barrier*

    SetEvent(dataIsPrepared);
        g_results.fun = FunCalculate(g_data);
    WaitForSingleObject(boringComplete);

    // Do something with g_results
}

Boring::Run()
{
    WaitForSingleObject(dataIsPrepared);
        g_results.boring = BoringCalculate(g_data);
        // *memory barrier*
    SetEvent(boringComplete);
}

Is there a "better" way to share data and results? Are there any red flags that stand out?

Thanks for any feedback.

\$\endgroup\$

migrated from stackoverflow.com Feb 16 '12 at 5:48

This question came from our site for professional and enthusiast programmers.

1
\$\begingroup\$

This is correct code. It could go into production.

You don't need the memory barrier because SetEvent will do that for you (if it didn't a lot of code would be broken).

You could change this to use futures (provided that you have some C++ lib that supports them. I don't really know C++ well):

var data = PrepareData();
var boringComputation = StartSomeFuture([&data] { ... });
var funComputation = ComputeFun(data);
var boringResult = boringComputation.ResultAndWait();

Much better.

\$\endgroup\$
0
\$\begingroup\$

Your code is correct.

Now that we got that out of the way, there is always a "better way" than using hand-coded synchronization, especially since what you are doing is in fact a producer-consumer pattern.

You can use for example Intel TBB which has some nice concurrent queue data structures (for example concurrent_bounded_queue) in order to easily share data between a producer and a consumer in a thread-safe manner.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy