Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running statements in 'parallel'

Tags:

c++

python

In python, I one had to swap values of 2 variables, all you need to do was

x,y=y,x

One can look at it as if the two statements-(x=y) and (y=x) are executed in parallel and not one after another.

Is there any way to achieve the same effect in c++?

NOTE/EDIT:

I am looking to extend this 'parallel effect' (if it exists) to more complicated expressions like
ones,twos= (ones ^ n) ^ ~twos, (ones & n) | (twos & ~n);

This is possible in python, is it possible in c++?

CONCLUSION:

So according to the answer given by leemes and the comments on his answer:

1.You can use boost libraries in C++03 or

2.You can use C++11

to access the std::tie and std::tuple to achieve this 'parallel' effect. As for the present, I mark leemes answer as accepted but I'll still be looking for methods to implement this cool functionality in C++03.

like image 795
sudeepdino008 Avatar asked Feb 09 '13 06:02

sudeepdino008


1 Answers

Special case: Swapping the value of two variables

(For the general solution, see below.)

To swap two variable's values in C++, you should always use swap:

using std::swap;
swap(x, y);      // Do NOT say:  std::swap(x, y)    -- Read about Koenig lookup!

Don't bother how it will do it; it will do it very fast. The implementation of the C++ standard library will do its best to optimize this to a single instruction if the processor supports it (but the standard doesn't tell the implementation to do so). For register-only variables, there is for example the x86 instruction xchg which will do it as fast as possible. Don't try to tweak it with some "three xor operations", it won't be any faster. If you're unlucky, it will not be optimized to something like xchg.

The generic swap operation in C++03 introduces a temporary variable and performs three copy constructions. In C++11 there are move-semantics and the objects are rather moved than copied. For your own types, let's say some data structure which holds only a pointer to the actual data, you should optimize this procedure to make it perform in constant time:

  • In C++03, you can either specialize std::swap or implement your own swap function in your namespace (see the two top answers on this question) to optimize swapping: Just swap each member in your class to swap their data. For the data structure example holding just a pointer, just swap the pointers.

  • In C++11, there are the new move semantics, which allow you to implement movement of the data from one to another object, which will result in a very similar behavior. (Move semantics have been introduced for more general problems like swapping two objects: If one object isn't needed anymore, but another one has to be a "copy" of the first, it can simply be moved.) Read about move semantics and move constructor for details.

  • For both C++03 and C++11 there is an alternative way: You can implement implicitly shared data and copy-on-write for heavy classes like data structures. In the example above, where your data structure holds a pointer to the actual data, implement reference counting. When copying the data structure, just increase the reference counter by one. When modifying the data, make sure that it isn't shared (ref count = 1), otherwise "detach" it by copying it only then. This results in a constant-time copy and swap operation.


General case: Multiple arbitrary expressions

For other statements which are not input/output dependent, like (a, b) = (x, y), just write them "as is", and it will run at least perfectly pipelined since they don't have any dependency:

a = x;
b = y;

If they are input/output dependent, like your example in the edit, you can split it up and introduce temporaries. You won't do yourself a favor by trying to solve such with some fancy expression tricks like xor-ing. The compiler knows a lot of tricks for assembler (like xchg), you only know tricks to express such in plain C++ (like xor).

In C++11, there is std::tuple and std::tie allowing you to assign multiple expressions without introducing temporaries (they will be introduced behind the scenes to hold the values stored in the tuple and tries to optimize them either fully away or at least only using registers to hold them if possible):

using std::tie;
using std::make_tuple;
tie(ones, twos) = make_tuple((ones ^ n) ^ ~twos, (ones & n) | (twos & ~n));

Note that the types of the right hand side pair / tuple has to match the target values on the left hand side as conversion isn't implicit here. If you encounter problems, perform a static_cast on the right hand side, tell std::make_tuple the explicit types or just use the constructor for std::tuple requiring explicit types, like:

using std::tie;
using std::tuple;
tie(ones, twos) = tuple<int,int>((ones ^ n) ^ ~twos, (ones & n) | (twos & ~n));
like image 137
leemes Avatar answered Nov 12 '22 13:11

leemes