#include <iostream>
#include <iomanip>
#include <chrono>
#include <limits>
#include <omp.h> // OMP functions
#include <mutex>

std::mutex m1;

std::string concatenate( std::string a, std::string b ) { // a is the total
    m1.lock();
    std::cout << a << " + " << b << " = ";
    std::string r = a+b;
    std::cout << r << std::endl;
    m1.unlock();
	return r;
}

#pragma omp declare reduction \
	(concatenate:std::string:omp_out=concatenate(omp_out,omp_in)) \
initializer(omp_priv="")


// user defined types are OK too

int main()
{
    std::string m;
#pragma omp parallel for reduction(concatenate:m) schedule(static,5)
	for ( int i=0; i<50; ++i ) {
        std::string s = " ";
        s += std::to_string(i);
		m = concatenate( m, s );
	}
	std::cout << m << std::endl;

}