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++
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
- Heiko Bauke (01.07.2009 22:39)
- Georg Gast (02.07.2009 17:16)
