Sebastian Hoffmann
Sebastian Hoffmann

Reputation: 11482

OpenMp: Threadlocal member

I am currently working on a piece of code written by a former colleague which utilizes OpenMP. Myself however has no experience with OpenMP and while I understand the very basics by just reading his code, I'm currently stuck figuring out how to declare a threadlocal member for my own modification.

The current code in a very simplified version looks like this:

struct Worker
{
    void work() { //... }
};

-------------------------------------------------------------------

Worker worker;

#pragma omp parallel for
for (int i = 0; i < n; ++i)
{
    worker.work();
}

What I want to acheive is to modify the Worker class in a way similiar to this:

struct Worker
{
    void work() { // m_var is accessed here }
    
    int m_var; // should be threadlocal
};

However I have no clue how to achieve this using OpenMP. Notice that all other members inside Worker should not be synchronized or threadlocal.

PS: For those who are curious, Worker is actually a class to download some complicated stuff and in the for loop the single downloads are performed. m_var is going to be an object holding a session.

Upvotes: 0

Views: 3511

Answers (2)

Mikhail T.
Mikhail T.

Reputation: 3997

Should the static requirement be unacceptable for your situation, you can to replace your int field with a class of its own -- the class can be private to your Worker, or you can make it a template to be reused with different fields in different classes.

Either way, the new class's constructor will allocate an array -- as long as there are OpenMP-threads (let's call it int_array):

    ThreadedInt() {
        int_array = new int[omp_get_max_threads()];
    }

You will also implement the operators necessary to cast this new class into the original type (int in your example). For example:

    operator int() const {
        return int_array[omp_get_thread_num()];
    }

as well as some others, such as assignment:

    int& operator = (int value) {
        return int_array[omp_get_thread_num()] = value;
    }

then the rest of your code can remain unmodified, OpenMP or not.

Upvotes: 0

Hristo Iliev
Hristo Iliev

Reputation: 74395

Non-static data members have separate instances in each instance of the class and cannot be thread-local - they inherit the sharing class of the concrete object of the given class. For example, if an object of class Worker is created on the stack of an OpenMP thread (i.e. the object has an automatic storage class), then the object itself is private to that thread and worker.m_var is also private. If the object is created on the heap, it could be shared with other threads and worker->m_var will then be shared too.

Thread-private can only be applied to data members with static storage class:

struct Worker
{
    void work();

    static int m_var;
    #pragma omp threadprivate(m_var)
};

int Worker::m_var;

In that case only one static (global) copy of Worker::m_var exists and it making it thread-private gives each thread a separate instance shared between all instances of Worker in that thread.

Also note that private and firstprivate cannot be applied to class data members, no matter if they are static or not - see this answer.

Upvotes: 3

Related Questions