Community
cancel
Showing results for 
Search instead for 
Did you mean: 
nuntawat
Beginner
37 Views

Modification variable in operator() method

I would like to modify the value of the object inside operator method look like this:

[cpp]class Case {
  int sampleVar;
public:
  void operator() (const blocked_range& range) const {
    for(int i = range.begin(), i != range.end(), i++) {
      // do some tasks
      sampleVar++;
    }
  }

  Case(int sampleVar): sampleVar(sampleVar) {}
};[/cpp]

but because the operator method must be declared const keyword, so I cannot modify the value. What should I do?
0 Kudos
12 Replies
RafSchietekat
Black Belt
37 Views

mutable int sampleVar;
Dmitry_Vyukov
Valued Contributor I
37 Views

Quoting - Raf Schietekat
mutable int sampleVar;

AFAIR, functor can be executing and concurrently coping. If so, mutable is not the way. If only single variable of primitive type is copied, then mutable tbb::atomic can be used. Otherwise, mutex must be used in operator() and copy ctor.

RafSchietekat
Black Belt
37 Views

I don't know, I didn't feel like speculating about the context at this time, but I don't think I would try copying atomics myself, concurrently or otherwise.

Meanwhile, there's this pipeline thing that I don't care to look at again for at least a month, so maybe you could shine your light on that, too?
Dmitry_Vyukov
Valued Contributor I
37 Views

Quoting - Raf Schietekat
I don't know, I didn't feel like speculating about the context at this time, but I don't think I would try copying atomics myself, concurrently or otherwise.


What do you mean?

Dmitry_Vyukov
Valued Contributor I
37 Views

Quoting - Raf Schietekat
Meanwhile, there's this pipeline thing that I don't care to look at again for at least a month, so maybe you could shine your light on that, too?

There is so many unconnected questions/answers/discussions, what exactly moment do you mean?

RafSchietekat
Black Belt
37 Views

"What do you mean?" Maybe I should have another look at it (and explain the fifth line), but I wrote these comments in my "Additions to atomic" proposal:

// About copy constructors and copy assignment operators:
// Normally these must be defined together for consistency.
// Atomics cannot have copy constructors because that would also require the definition of a default constructor,
// which would interfere with the expectation that atomics are ready for use right after static initialization;
// any use of a(n implicitly defined) copy constructor should be avoided, however.
// They must have copy assignment operators to invoke store(), because, unlike the situation with constructors,
// a copy assignment operator will be implicitly defined even if another user-defined assignment operator exists,
// and selectively restricting assignment would only invite accidental use of a (non-atomic) implicit definition.
// TODO: double check the last statement

On a related topic, I also wrote this (reformatted):

// default-initialization does not translate to zero-initialization because atomic is non-POD
// because it has a copy assignment operator, which means that putting my_atomic()
// in an initializer list or doing "tbb::atomic a; a = tbb::atomic();"
// is incorrect (it doesn't do what it seems to be expected to do).

What do you think?

"There is so many unconnected questions/answers/discussions, what exactly moment do you mean?"

See "Pipeline" thread: I published a code snapshot, but it doesn't work yet, and I need to take a break from it myself to regain a fresh perspective.
Dmitry_Vyukov
Valued Contributor I
37 Views

Quoting - Raf Schietekat
"What do you mean?" Maybe I should have another look at it (and explain the fifth line), but I wrote these comments in my "Additions to atomic" proposal:

// About copy constructors and copy assignment operators:
// Normally these must be defined together for consistency.
// Atomics cannot have copy constructors because that would also require the definition of a default constructor,
// which would interfere with the expectation that atomics are ready for use right after static initialization;
// any use of a(n implicitly defined) copy constructor should be avoided, however.
// They must have copy assignment operators to invoke store(), because, unlike the situation with constructors,
// a copy assignment operator will be implicitly defined even if another user-defined assignment operator exists,
// and selectively restricting assignment would only invite accidental use of a (non-atomic) implicit definition.
// TODO: double check the last statement

On a related topic, I also wrote this (reformatted):

// default-initialization does not translate to zero-initialization because atomic is non-POD
// because it has a copy assignment operator, which means that putting my_atomic()
// in an initializer list or doing "tbb::atomic a; a = tbb::atomic();"
// is incorrect (it doesn't do what it seems to be expected to do).

What do you think?



I think that functor's copy ctor must be defined explicitly:


struct functor
{
tbb::atomic x;
...
functor(functor const& f)
{
x.store(f.x.load(relaxed), relaxed);
}
};


Dmitry_Vyukov
Valued Contributor I
37 Views

Quoting - Raf Schietekat
"There is so many unconnected questions/answers/discussions, what exactly moment do you mean?"

See "Pipeline" thread: I published a code snapshot, but it doesn't work yet, and I need to take a break from it myself to regain a fresh perspective.

I see the attachment in the last post, and I have skimmed over the thread, but I don't get what problem the attachment tries to solve, or what it tries to improve. What it's all about?

RafSchietekat
Black Belt
37 Views

"I think that functor's copy ctor must be defined explicitly" Maybe, but I just didn't want to speculate on what's going on here (I did think about suggesting "tbb::atomic *sampleVar;", but I decided instead to wait and see).

RafSchietekat
Black Belt
37 Views

Quoting - Dmitriy Vyukov

I see the attachment in the last post, and I have skimmed over the thread, but I don't get what problem the attachment tries to solve, or what it tries to improve. What it's all about?


Over to "Pipeline"...
ARCH_R_Intel
Employee
37 Views

Yes, the functor body might be copied by the implementation of parallel_for. The simplest solution is pass sampleVar by reference and make sampleVar atomic, as shown below:

[cpp]class Case {   
  atomic& sampleVar;   
public:   
  void operator() (const blocked_range& range) const {   
    for(int i = range.begin(), i != range.end(), i++) {   
      // do some tasks   
      sampleVar++;   
    }   
  }   
  
  Case(atomic& sampleVar_): sampleVar(sampleVar_) {}   
}; [/cpp]
[cpp][/cpp]

Another option, which works if sampleVar is not being read until the parallel loop completes, is to use parallel_reduce. Using paralle_reduce this way may improve performance, because it allows you to accumulate in local copies of sampleVar and then sum them. Look at file examples/parallel_reduce/primes/primes.cpp in the TBB ditribution. Inside there is a class Sieve that tallies a counter variable "count". You can tally sampleVar in a similar way. Be sure to inspect how method Sieve(Sieve&&,split) initializes a local count and method Sieve::join sums two local counts.
Alexey_K_Intel3
Employee
37 Views

Another option, which works if sampleVar is not being read until the parallel loop completes, is to use parallel_reduce.

A side note: this reminded me of a suggestion I have heard earlier, which was for TBB algorithms, parallel_reduce in particular,to return a copy of the body object. This object can then be assigned to some variable, and it might have a conversion operator so that the following could be written:
int my_sum = parallel_reduce(blocked_range(0,N), MySummationBody(my_array), auto_partitioner());
Reply