nntp2http.com
Posting
Suche
Optionen
Hilfe & Kontakt

Schleifenparallelisierung mit boost

Von: Georg Gast (schorsch_76@gmx.de) [Profil]
Datum: 01.07.2009 19:47
Message-ID: <h2g7fq$bfh$1@online.de>
Newsgroup: de.comp.lang.iso-c++
Hallo NG,

momentan beschäftige ich mich mit Schleifenparalleisierung mit Boost
Threads. In OpenMP drückt man das wohl so aus:

<code OpenMP>
#pragma omp parallel for reduction (+ : sum)
for (int i = 0; i < 1000; ++i)
{
// do stuff
sum = sum + i;
}
</code OpenMP>

Das scheint ja ganz einfach ;) Jetzt wollte ich das ganze mit
Boost::Threads programmieren. Meine Idee war 2 Funktor Objekte zu
verwenden. Eines um die einzelnen Thread die Execute Funktion in den
operator() zu packen. Das nächste dann für die Addition der Teilsummen.

Hier mein Code. Inspiriert wurde das ganze von Boris Schäling's
Boostbuch und seiner Aufgabe 1 + 2 im Kapitel über Multithreading.
http://www.highscore.de/cpp/boost/multithreading.html

<code boost::Thread>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <iostream>

// Functor for the Thread
class Sum
{
public:
Sum(boost::uint64_t start, boost::uint64_t end)
:	m_sum(0),
m_start(start),
m_end(end)
{}
~Sum()	{}

// operator for the thread
void	operator()()
{
for (boost::uint64_t i = m_start; i < m_end; ++i)
m_sum += i;
}

operator boost::uint64_t()
{
return m_sum;
}

private:
boost::uint64_t	m_sum;
boost::uint64_t	m_start;
boost::uint64_t	m_end;
};

// functor after join
class AfterSum
{
public:
AfterSum()
:	m_sum(0)
{
}
~AfterSum()
{
}

// operatior for "for_each"
void	operator()(boost::uint64_t elem)
{
m_sum += elem;
}

operator boost::uint64_t()
{
return m_sum;
}
private:
boost::uint64_t	m_sum;
};

// functor for the creation of threads
template <class FuncThread, class FuncAfter>
class ForThreadMgr
{
public:
ForThreadMgr(boost::int64_t start, boost::uint64_t end, size_t thread_cnt)
:	m_start(start),
m_end(end),
m_thread_cnt(thread_cnt)
{
// create functor for the threads
boost::uint64_t	fs;
boost::uint64_t	fe;

boost::uint64_t delta = (m_end-m_start)/m_thread_cnt;
for (size_t i = 0; i < m_thread_cnt; ++i)
{
fs = i * delta;
fe = (i <= thread_cnt - 1)	? (i + 1) * delta :m_end;

m_thread_functors.push_back(FuncThread(fs,fe));
}

// start all threads
for (size_t i = 0; i < m_thread_cnt; ++i)
m_threads.add_thread(new
boost::thread(boost::bind(&FuncThread::operator(),&m_thread_functors[i])));

// join all threads
m_threads.join_all();
}
~ForThreadMgr()
{
}

operator boost::uint64_t()
{
// start the AfterFunctor
return
std::for_each(m_thread_functors.begin(),m_thread_functors.end(),FuncAfter());
}

private:
std::vector<FuncThread>	m_thread_functors;
size_t					m_thread_cnt;
boost::uint64_t			m_start;
boost::uint64_t			m_end;
boost::thread_group		m_threads;
};

int main()
{
boost::posix_time::ptime zeit_start
boost::posix_time::microsec_clock::local_time();
boost::uint64_t sum = 0;

ForThreadMgr<Sum, AfterSum>
mgr(0,1000000000,boost::thread::hardware_concurrency());
sum = mgr;

boost::posix_time::ptime zeit_end
boost::posix_time::microsec_clock::local_time();
std::cout << zeit_end - zeit_start << std::endl;

std::cout << sum << std::endl;

return 0;
}
</code boost::Thread>

Irgendwie gefällt mir das ganze noch nicht. Was könnte man besser machen?

Punkte die mir noch nicht gefallen:
* Die Funktorobjekte für die Threads brauchen Argumente im Konstruktor.
* Der ForThreadMgr muss wissen wie die ThreadFunktor Objekte konstruiert
werden (Argumente im Konstruktor)
* Sollte man die Threads erst starten, im operator boost::uint64_t()?
* Sollte der Datentyp(boost::uint64_t) noch als template argument
hinzugefügt werden?
* Könnte man das erzeugen der Funktorobjekte in eine Policy packen?

Achja hier noch meine Daten:
Vista x32 + x64
Visual Studio 2005 + 2008

Vorneweg schon mal vielen Dank für eure Antworten :D

Gruß

Georg

[ Auf dieses Posting antworten ]

Antworten