Hello,
   recently I played a little bit around with the C++11 thread features. I just
   modified BOINC's multi thread sample. In my opinion, C++11 enables me to
   create threads faster and more readable for Linux and Windows (I have no
   idea about Mac support). Attached you will find the source and makefile.
   Cheers
   Christian
# This should work on Linux.  Modify as needed for other platforms.

BOINC_DIR = ../..
BOINC_API_DIR = $(BOINC_DIR)/api
BOINC_LIB_DIR = $(BOINC_DIR)/lib

CXXFLAGS = -std=c++0x -g \
    -I$(BOINC_DIR) \
    -I$(BOINC_LIB_DIR) \
    -I$(BOINC_API_DIR) \
    -L$(BOINC_API_DIR) \
    -L$(BOINC_LIB_DIR) \
    -L.

PROGS = multi_thread-c++11

all: $(PROGS)

libstdc++.a:
        ln -s `g++ -print-file-name=libstdc++.a`

clean:
        /bin/rm -f $(PROGS)

distclean:
        /bin/rm -f $(PROGS) *.o libstdc++.a

multi_thread-c++11: multi_thread-c++11.o libstdc++.a 
$(BOINC_API_DIR)/libboinc_api.a $(BOINC_LIB_DIR)/libboinc.a
        $(CXX) $(CXXFLAGS) -o multi_thread-c++11 multi_thread-c++11.o 
libstdc++.a -pthread -lboinc_api -lboinc
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.

//
// Contributor: Christian Benjamin Ries ([email protected])
// This file is based on BOINC's basic thread example
// in samples/multi_thread. Here, this version is changed for
// the use of C++11 threads support.
// On some systems you have to enable C++0x support:
//   g++ -std=c++0x ...
// 

// Example multi-thread BOINC application with the use of C++11 threads.
// This app defines its own classes (Worker, Threads) for managing C++11 threads.
// You can also use libraries such as OpenMP.
// Just make sure you call boinc_init_parallel().
//
// This app does 64 "units" of computation, where each units is about 1 GFLOP.
// It divides this among N "worker" threads.
// N is passed in the command line, and defaults to 1.
//
// Doesn't do checkpointing.

// C
#include <stdio.h>

// C++
#include <map>
#include <thread>
#include <sstream>
#include <iostream>

// Windows
#ifdef _WIN32
#include "boinc_win.h"
#endif

// BOINC
#include "util.h"
#include "str_util.h"
#include "boinc_api.h"

#define DEFAULT_NTHREADS 4
#define TOTAL_UNITS 16

class Worker {
private:
	int _unitsPerThread;
	int _unitsDone;
	bool _done;
public:
	Worker(int upt) : _unitsPerThread(upt), _done(false) {}
	int unitsDone() const { return _unitsDone; }
	bool done() const { return _done; }

	void operator()() {
		for (int i=0; i<_unitsPerThread; i++) {
			double x = do_a_giga_flop(i);
			_unitsDone++;

			//std::this_thread::sleep_for(std::chrono::seconds(3));

			char buf[256] {'\0'};
			std::stringstream s;
			s << boinc_msg_prefix(buf, sizeof(buf))
			  << " thread " << std::this_thread::get_id()
			  << " finished " << i << ": " << x << std::endl;
			std::cerr << s.str();
		}
		_done = true;
	}

	// do a billion floating-point ops
	// (note: I needed to add an arg to this;
	// otherwise the MS C++ compiler optimizes away
	// all but the first call to it!)
	//
	static double do_a_giga_flop(int foo) {
		double x = 3.14159*foo;
		int i;
		for (i=0; i<500000000; i++) {
			x += 5.12313123;
			x *= 0.5398394834;
		}
		return x;
	}	
};

class Threads 
	: public std::map<std::thread*, Worker*>
{
public:
	bool all_done() {
		for( auto it : *this) {
			if(!it.second->done()) 
				return false;
		}
		return true;
	}

	int units_done() {
		int count = 0;
		for(auto it : *this) {
			count += it.second->unitsDone();
		}
		return count;
	}

	void join() {
		for(auto it : *this) {
			it.first->join();
		}
	}
};

int main(int argc, char** argv) {
    auto i(0), nthreads(DEFAULT_NTHREADS);
    auto start_time = dtime();
    char buf[256] = {'\0'};

    BOINC_OPTIONS options;
    boinc_options_defaults(options);
    options.multi_thread = true;
    boinc_init_options(&options);

    for (i=1; i<argc; i++) {
        if (!strcmp(argv[i], "--nthreads")) {
            nthreads = atoi(argv[++i]);
        } else {
            fprintf(stderr, "%s unrecognized arg: %s\n",
                boinc_msg_prefix(buf, sizeof(buf)), argv[i]
            );
        }
    }

    auto units_per_thread = TOTAL_UNITS / nthreads;

    Threads threads;
    for (i=0; i<nthreads; i++) {
			auto w = Worker(units_per_thread);
			auto t = new std::thread(std::ref(w));
			threads[t] = &w;
    }
    
		while (1) {
        double f = threads.units_done()/((double)TOTAL_UNITS);
        boinc_fraction_done(f);
        if(threads.all_done()) break;
        boinc_sleep(1.0);
    }

		threads.join();

    auto elapsed_time = dtime() - start_time;
		std::stringstream s;
		s << boinc_msg_prefix(buf, sizeof(buf))
			<< " All done. Used " << nthreads << " threads."
			<< " Elapsed time " << elapsed_time << std::endl;
		std::cerr << s.str();

    boinc_finish(0);
}

#ifdef _WIN32
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) {
    LPSTR command_line;
    char* argv[100];
    int argc;

    command_line = GetCommandLine();
    argc = parse_command_line( command_line, argv );
    return main(argc, argv);
}
#endif

_______________________________________________
boinc_dev mailing list
[email protected]
http://lists.ssl.berkeley.edu/mailman/listinfo/boinc_dev
To unsubscribe, visit the above URL and
(near bottom of page) enter your email address.

Reply via email to