False exchanges and stack variables

I have small but commonly used function objects. Each thread gets its own copy. Everything is distributed statically. Copies do not apply to global or static data. Do I need to protect these objects from false exchange?

Thanks. EDIT: Here is a toy program that uses Boost.Threads. Can there be false sharing for a data field?

#include <boost/thread/thread.hpp> struct Work { void operator()() { ++data; } int data; }; int main() { boost::thread_group threads; for (int i = 0; i < 10; ++i) threads.create_thread(Work()); threads.join_all(); } 
+7
c ++ false-sharing
source share
3 answers

False separation between threads is that two or more threads use the same cache line.

eg.

 struct Work { Work( int& d) : data( d ) {} void operator()() { ++data; } int& data; }; int main() { int false_sharing[10] = { 0 }; boost::thread_group threads; for (int i = 0; i < 10; ++i) threads.create_thread(Work(false_sharing[i])); threads.join_all(); int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 }; for (int i = 0; i < 10; ++i) threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS])); threads.join_all(); } 

The flows in the first block really suffer from a false exchange. Threads in the second block are not (thanks to CACHELINE_SIZE ).

Stack data is always "far" from other threads. (For example, under the windows, at least a couple of pages).

False sharing may appear with your definition of a function object, because Work instances are created on the heap, and this heap space is used inside the stream.

This can cause multiple Work instances to be contiguous and therefore can share cache lines.

But ... your sample does not make sense, because the data is never affected externally, and therefore false sharing is useless to induce.

The easiest way to prevent such problems is to copy your β€œshared” data locally onto the stack, and then work with a copy of the stack. When your work is finished, copy it back to the var output.

For example:

 struct Work { Work( int& d) : data( d ) {} void operator()() { int tmp = data; for( int i = 0; i < lengthy_op; ++i ) ++tmp; data = tmp; } int& data; }; 

This prevents all sharing issues.

+6
source share

I have done quite a bit of research, and there seems to be no false solution for a silver bullet. Here's what I came up with (thanks to Christopher): 1) Put your data on both sides on unused or less frequently used materials. 2) Copy your data onto the stack and copy it after all the hard work is done. 3) Use the allocated memory allocation using the cache.

+2
source share

I do not feel completely safe with the details, but here I take:

(1) Your simplified example is broken, because boost create_thread expects a link, you are passing a temporary one.

(2) if you use vector<Work> with one element for each thread or, conversely, have them in memory sequentially, false sharing will occur.

0
source share

All Articles