Concentrated all files into src, previously it was under its own active-object sub-repository

This commit is contained in:
Kjell Hedstrom 2011-11-05 23:19:49 +01:00
parent b9459af2f3
commit fa9e5b4adf
13 changed files with 134 additions and 436 deletions

View File

@ -1,70 +0,0 @@
# ================WINDOWS==================
# On Windows
# mkdir build; cd build;
# cmake -G "Visual Studio 10" ..
# msbuild ActiveObj_by_KjellKod.sln
# Debug\ActiveObj_by_KjellKod.exe
#
#
# ================LINUX==================
# On Linux, make sure that the environmental variables are set either in .profile or otherwise
# PATH=$PATH:/usr/include/justthread
# export PATH=/usr/lib/:$PATH
#
# from a++0x__active_object do
# mkdir build; cd build; cmake ..; make
#
# In case of CMake problems, Compile command line
#g++ src/main.cpp src/active.cpp -I /home/kjhm/Desktop/KjellKod/active-object_c++0x/src -o ActiveObj -std=c++0x -I/usr/include/justthread -pthread -ljustthread -lrt
#
# Or to simplify things even more, put all the source code in the same folder and run
# g++ main.cpp active.cpp -o ActiveObj -std=c++0x -I/usr/include/justthread -pthread -ljustthread -lrt
#
#
cmake_minimum_required (VERSION 2.6)
project (ActiveObjCpp0x)
IF(UNIX)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS_DEBUG} -pthread -I/usr/include/justthread")
# make the src directory available for test classes
include_directories("/usr/include/justthread")
include_directories(../src)
# create the test executable
#add_executable(ActiveObjCpp0x ../src/main.cpp ../src/active.cpp )
add_executable(ActiveObjCpp0x ../src/main.cpp ../src/active.cpp ../src/shared_queue.h ../src/active.h ../src/backgrounder.h)
target_link_libraries(ActiveObjCpp0x justthread rt)
ENDIF(UNIX)
IF(WIN32)
include_directories("C:/program files/JustSoftwareSolutions/JustThread/include")
include_directories(../src)
add_executable(ActiveObjCpp0x ../src/main.cpp ../src/active.cpp )
#Visual Studio 2010
IF(CMAKE_CXX_COMPILER STREQUAL "C:/Program Files/Microsoft Visual Studio 10.0/VC/bin/cl.exe")
target_link_libraries(ActiveObjCpp0x $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10_mdd.lib)
ENDIF(CMAKE_CXX_COMPILER STREQUAL "C:/Program Files/Microsoft Visual Studio 10.0/VC/bin/cl.exe")
# Visual Studio 2008 DOES NOT WORK
# ===================================
# 1. std::function must be std::tr1::function but
# std::unique_ptr does not exist (ref C:\Program Files\Microsoft Visual Studio 9.0\VC\include\memory.h)
# while it exist for Visual Studio 10 (ref C:\Program Files\Microsoft Visual Studio 10.0\VC\include\memory.h)
# ...Also this bug was discovered...
# Ref: https://connect.microsoft.com/VisualStudio/feedback/details/339810/tr1-functional-doesnt-work-when-compiled-with-fastcall
#....
# However if you decide to use it anyhow and replacing the unique_ptr for shared_ptr and using std::tr1 then the
# following might be of use
#IF(CMAKE_CXX_COMPILER STREQUAL "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin/cl.exe")
# target_link_libraries(ActiveObjCpp0x $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc90_mdd.lib)
#ENDIF(CMAKE_CXX_COMPILER STREQUAL "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin/cl.exe")
ENDIF(WIN32)

View File

@ -1,21 +0,0 @@
# ================WINDOWS==================
# On Windows
# mkdir build; cd build;
# cmake -G "Visual Studio 10" ..
# msbuild ActiveObj_by_KjellKod.sln
# Debug\ActiveObj_by_KjellKod.exe
#
#
# ================LINUX==================
# On Linux, make sure that the environmental variables are set either in .profile or otherwise
# PATH=$PATH:/usr/include/justthread
# export PATH=/usr/lib/:$PATH
#
# from the top directory (active-object_c++0x)
# mkdir build; cd build; cmake ..; make
#
# In case of CMake problems, Compile command line
#g++ src/main.cpp src/active.cpp -I /home/kjhm/Desktop/KjellKod/active-object_c++0x/src -o ActiveObj -std=c++0x -I/usr/include/justthread -pthread -ljustthread -lrt
#
# Or to simplify things even more, put all the source code in the same folder and run
# g++ main.cpp active.cpp -o ActiveObj -std=c++0x -I/usr/include/justthread -pthread -ljustthread -lrt

View File

@ -1,59 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Example of a Background worker that uses an Active object (by composition)
* to process jobs in the background.
* Calling the Background worker to do a job is an asynchronous call, returning
* almost immediately. The Backgrounder will create a job and push it onto a
* queue that is processed in FIFO order by the Active object. */
#include <vector>
#include <chrono>
#include <memory>
#include "active.h"
/// Silly test background worker that only receives dummy encapsuled data and stores them in a vector
/// the worker eceives the "jobs" and sends them to a work queue to be asynchronously
// executed in FIFO order by the background thread.
template<typename T>
class Backgrounder {
private:
std::unique_ptr<kjellkod::Active> active;
std::vector<T>& receivedQ;
unsigned int c_processTimeUs; // to fake processing time, in microseconds
// Container for faking some imporant stuff type instead of a dummy value
// so that it 'makes sense' storing it in an unique_ptr
struct Data {
Data(T v_) :value(v_) {}
const T value;
};
// bg processing, FAKING that each job takes a few ms
void bgStoreData(std::shared_ptr<Data> msg_){
receivedQ.push_back(msg_->value);
// fake processing time
std::this_thread::sleep_for(std::chrono::microseconds(c_processTimeUs));
}
public:
explicit Backgrounder(std::vector<T>& saveQ_)
: active(kjellkod::Active::createActive())
, receivedQ(saveQ_)
, c_processTimeUs(1){}
virtual ~Backgrounder(){}
// Asynchronous msg API, for sending jobs for bg thread processing
void saveData(const T value_){
using namespace kjellkod;
std::shared_ptr<Data> ptrBg(new Data(value_));
Callback func = std::bind(&Backgrounder::bgStoreData, this, ptrBg);
active->send(func);
}
};

View File

@ -1,130 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Please See readme or CMakeList.txt for building instructions */
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <thread>
#include <memory>
#include <cmath>
#include <ctime>
#include <cassert>
#include "backgrounder.h"
namespace {
void printPercentageLeft(const unsigned nbr_, unsigned & progress_, const unsigned max_){
float percent = 100 * ((float)nbr_/max_);
unsigned int rounded = ((int)percent/10)*10;
if(rounded != progress_){
std::cout << 100 - progress_ << " " << std::flush;
progress_ = rounded;
return;
}
}
template<typename T>
void printProgress(const std::vector<T>& out_,const std::vector<T>& in_, const unsigned max_)
{
std::cout << "\nLeft to Process [%]: ";
unsigned progress = 100;
do{
unsigned pSize = in_.size();
unsigned remaining = pSize - out_.size();
printPercentageLeft(remaining, progress, max_);
}while((out_.size() < max_) && progress <= 100);
}
}
void runStrWorkers(const int c_nbrItems)
{
std::vector<std::string> saveToQ;
std::vector<std::string> compareQ;
const clock_t start = clock();
{
Backgrounder<std::string> worker(saveToQ);
srand((unsigned)time(0));
for(int idx=0; idx < c_nbrItems; ++idx)
{
unsigned random = rand();
std::ostringstream oss;
oss << random;
compareQ.push_back(oss.str());
worker.saveData(oss.str());
}
double pushTime = ((clock() - start)/(double)CLOCKS_PER_SEC);
std::cout<<"Finished pushing #"<<c_nbrItems<<" jobs to bg worker";
std::cout<<" in "<<pushTime<<" [s]"<< std::endl;
printProgress(saveToQ, compareQ, c_nbrItems);
} // Trigger Backgrounder to go out of scope
double workTime = ((clock() - start)/(double)CLOCKS_PER_SEC);
std::cout << "\nBackgrounder finished with processing jobs in ";
std::cout <<workTime<<" [s]"<< std::endl;
// just dummy to make sure that nothing was lost
assert(std::equal(compareQ.begin(), compareQ.end(), saveToQ.begin()));
assert(saveToQ.size() == c_nbrItems);
}
void runIntWorkers(const int c_nbrItems)
{
std::vector<int> saveToQ;
std::vector<int> compareQ;
const clock_t start = clock();
{
Backgrounder<int> worker(saveToQ);
srand((unsigned)time(0));
// all except one is random, save space for "zero" after the
// loop
for(int idx=0; idx < c_nbrItems-1; ++idx)
{
unsigned random = rand();
compareQ.push_back(random);
worker.saveData(random);
}
// extra case for empty item
compareQ.push_back(0);
worker.saveData(0);
double pushTime = ((clock() - start)/(double)CLOCKS_PER_SEC);
std::cout<<"Finished pushing #"<<c_nbrItems<<" jobs to bg worker";
std::cout<<" in "<<pushTime<<" [s]"<< std::endl;
printProgress(saveToQ, compareQ, c_nbrItems);
} // Trigger Backgrounder to go out of scope
double workTime = ((clock() - start)/(double)CLOCKS_PER_SEC);
std::cout << "\nBackgrounder finished with processing jobs in ";
std::cout<<" in "<<workTime<<" [s]"<< std::endl;
// just dummy to make sure that nothing was lost
assert(std::equal(compareQ.begin(), compareQ.end(), saveToQ.begin()));
assert(saveToQ.size() == c_nbrItems);
}
int main(int argc, char** argv)
{
const int c_nbrItems = 100000;
std::cout << c_nbrItems << " transactions of std::string/int" << std::endl;
runStrWorkers(c_nbrItems);
std::cout << "\n\n" << c_nbrItems << " transactions of int" << std::endl;
runIntWorkers(c_nbrItems);
return 0;
}

View File

@ -50,7 +50,7 @@ IF(UNIX)
include_directories(/usr/include/justthread) #not necessarily needed if it's in the path
# add a ActiveObject library
set(ACTIVE_DIR ${LOG_SRC}/../../active-object_c++0x/src)
set(ACTIVE_DIR ${LOG_SRC})
include_directories(${ACTIVE_DIR})
MESSAGE(" ACTIVE_DIR = : ${ACTIVE_DIR}")
SET(ACTIVE_CPP0xx_DIR "Release")
@ -61,7 +61,7 @@ IF(UNIX)
include_directories(src)
include_directories(${LOG_SRC})
#MESSAGE(" LOG_SRC = : ${LOG_SRC}")
add_library(lib_logger ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/privatelogworker.cpp ${LOG_SRC}/privatelogworker.h ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp )
add_library(lib_logger ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp )
set_target_properties(lib_logger PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(lib_logger lib_activeobject)

View File

@ -7,26 +7,149 @@
#include "logworker.h"
#include <iostream>
#include <string>
#include <functional>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <cassert>
#include <iomanip>
#include <ctime>
#include "privatelogworker.h"
#include "active.h"
#include "g2log.h"
using namespace g2::internal;
namespace
{
struct LogTime
{
LogTime()
{
time_t current_time = time(nullptr);
ctime(&current_time); // fill with time right now
struct tm* ptm = localtime(&current_time); // fill time struct with data
year = ptm->tm_year + 1900;
month = (ptm->tm_mon) +1;
day = ptm->tm_mday;
hour = ptm->tm_hour;
minute = ptm->tm_min;
second = ptm->tm_sec;
}
int year; // Year - 1900
int month; // [1-12]
int day; // [1-31]
int hour; // [0-23]
int minute; // [0-59]
int second; // [0-60], 1 leap second
};
} // end anonymous namespace
/** The actual background worker, while LogWorker gives the
* asynchronous API to put job in the background the LogWorkerImpl
* does the actual background thread work */
struct LogWorkerImpl
{
LogWorkerImpl(const std::string& log_prefix, const std::string& log_directory);
~LogWorkerImpl();
void backgroundFileWrite(g2::internal::LogEntry message);
std::string log_file_with_path_;
std::unique_ptr<kjellkod::Active> bg_;
std::ofstream out;
g2::internal::time_point start_time_;
private:
LogWorkerImpl& operator=(const LogWorkerImpl&) = delete; // no assignment, no copy
LogWorkerImpl(const LogWorkerImpl& other) = delete;
};
//
// Private API implementation : LogWorkerImpl
LogWorkerImpl::LogWorkerImpl(const std::string& log_prefix, const std::string& log_directory)
: log_file_with_path_(log_directory)
, bg_(kjellkod::Active::createActive())
, start_time_(std::chrono::steady_clock::now())
{
using namespace std;
LogTime t;
ostringstream oss_name;
oss_name.fill('0');
oss_name << log_prefix << ".g2log.";
oss_name << t.year << setw(2) << t.month << setw(2) << t.day;
oss_name << "-" << setw(2) << t.hour << setw(2) << t.minute << setw(2) << t.second;
oss_name << ".log";
log_file_with_path_ += oss_name.str();
// open the log file
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
mode |= std::ios_base::trunc;
out.open(log_file_with_path_, mode);
if(!out.is_open())
{
std::ostringstream ss_error;
ss_error << "Fatal error could not open log file:[" << log_file_with_path_ << "]";
ss_error << "\n\t\t std::ios_base state = " << out.rdstate();
std::cerr << ss_error.str().c_str() << std::endl << std::flush;
assert(false && "cannot open log file at startup");
}
std::ostringstream ss_entry;
time_t creation_time;
time(&creation_time);
ss_entry << "\t\tg2log created log file at: " << ctime(&creation_time);
ss_entry << "\t\tLOG format: [YYYY/MM/DD hh:mm:ss.uuu* LEVEL FILE:LINE] message\n\n";
out << ss_entry.str() << std::flush;
out.fill('0');
}
LogWorkerImpl::~LogWorkerImpl()
{
std::ostringstream ss_exit;
time_t exit_time;
time(&exit_time);
bg_.reset(); // flush the log queue
ss_exit << "\n\t\tg2log file shutdown at: " << ctime(&exit_time);
out << ss_exit.str() << std::flush;
}
void LogWorkerImpl::backgroundFileWrite(LogEntry message)
{
using namespace std;
LogTime t;
auto timesnapshot = chrono::steady_clock::now();
out << "\n" << t.year << "/" << setw(2) << t.month << "/" << setw(2) << t.day;
out << " " << setw(2) << t.hour << ":"<< setw(2) << t.minute <<":"<< setw(2) << t.second;
out << "." << chrono::duration_cast<microsecond>(timesnapshot - start_time_).count(); //microseconds
out << "\t" << message;
}
// BELOW LogWorker
// Public API implementation
LogWorker::LogWorker(const std::string& log_prefix, const std::string& log_directory)
: background_worker_(new PrivateLogWorker(log_prefix, log_directory))
, log_file_with_path_(background_worker_->log_file_with_path_)
: pimpl_(new LogWorkerImpl(log_prefix, log_directory))
, log_file_with_path_(pimpl_->log_file_with_path_)
{
}
LogWorker::~LogWorker()
{
background_worker_.reset();
pimpl_.reset();
//std::cout << "\nLogWorker finished with log: " << log_file_with_path_ << std::endl << std::flush;
}
void LogWorker::save(g2::internal::LogEntry msg)
{
background_worker_->bg_->send(std::tr1::bind(&PrivateLogWorker::backgroundFileWrite, background_worker_.get(), msg));
pimpl_->bg_->send(std::tr1::bind(&LogWorkerImpl::backgroundFileWrite, pimpl_.get(), msg));
}

View File

@ -7,13 +7,10 @@
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */
#include <string>
#include <memory>
#include "g2log.h"
class PrivateLogWorker;
class LogWorkerImpl;
/**
* \param log_prefix is the 'name' of the binary, this give the log name 'LOG-'name'-...
@ -31,7 +28,7 @@ public:
std::string logFileName() const;
private:
std::unique_ptr<PrivateLogWorker> background_worker_;
std::unique_ptr<LogWorkerImpl> pimpl_;
const std::string log_file_with_path_;
LogWorker(const LogWorker&) = delete; // no assignment, no copy

View File

@ -1,101 +0,0 @@
/* *************************************************
* Filename: privatelogworker.cpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */
#include "privatelogworker.h"
#include <sstream>
#include <iostream>
#include <cassert>
#include <iomanip>
#include <ctime>
using namespace g2::internal;
namespace
{
struct LogTime
{
LogTime()
{
time_t current_time = time(nullptr);
ctime(&current_time); // fill with time right now
struct tm* ptm = localtime(&current_time); // fill time struct with data
year = ptm->tm_year + 1900;
month = (ptm->tm_mon) +1;
day = ptm->tm_mday;
hour = ptm->tm_hour;
minute = ptm->tm_min;
second = ptm->tm_sec;
}
int year; // Year - 1900
int month; // [1-12]
int day; // [1-31]
int hour; // [0-23]
int minute; // [0-59]
int second; // [0-60], 1 leap second
};
} // end anonymous namespace
PrivateLogWorker::PrivateLogWorker(const std::string& log_prefix, const std::string& log_directory)
: log_file_with_path_(log_directory)
, bg_(kjellkod::Active::createActive())
, start_time_(std::chrono::steady_clock::now())
{
using namespace std;
LogTime t;
ostringstream oss_name;
oss_name.fill('0');
oss_name << log_prefix << ".g2log.";
oss_name << t.year << setw(2) << t.month << setw(2) << t.day;
oss_name << "-" << setw(2) << t.hour << setw(2) << t.minute << setw(2) << t.second;
oss_name << ".log";
log_file_with_path_ += oss_name.str();
// open the log file
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
mode |= std::ios_base::trunc;
out.open(log_file_with_path_, mode);
if(!out.is_open())
{
std::ostringstream ss_error;
ss_error << "Fatal error could not open log file:[" << log_file_with_path_ << "]";
ss_error << "\n\t\t std::ios_base state = " << out.rdstate();
std::cerr << ss_error.str().c_str() << std::endl << std::flush;
assert(false && "cannot open log file at startup");
}
std::ostringstream ss_entry;
time_t creation_time;
time(&creation_time);
ss_entry << "\t\tg2log created log file at: " << ctime(&creation_time);
ss_entry << "\t\tLOG format: [YYYY/MM/DD hh:mm:ss.uuu* LEVEL FILE:LINE] message\n\n";
out << ss_entry.str() << std::flush;
out.fill('0');
}
PrivateLogWorker::~PrivateLogWorker()
{
std::ostringstream ss_exit;
time_t exit_time;
time(&exit_time);
bg_.reset(); // flush the log queue
ss_exit << "\n\t\tg2log file shutdown at: " << ctime(&exit_time);
out << ss_exit.str() << std::flush;
}
void PrivateLogWorker::backgroundFileWrite(LogEntry message)
{
using namespace std;
LogTime t;
auto timesnapshot = chrono::steady_clock::now();
out << "\n" << t.year << "/" << setw(2) << t.month << "/" << setw(2) << t.day;
out << " " << setw(2) << t.hour << ":"<< setw(2) << t.minute <<":"<< setw(2) << t.second;
out << "." << chrono::duration_cast<microsecond>(timesnapshot - start_time_).count(); //microseconds
out << "\t" << message;
}

View File

@ -1,41 +0,0 @@
/* *************************************************
* Filename: privatelogworker.h Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */
#ifndef PRIVATE_LOG_WORKER_H_
#define PRIVATE_LOG_WORKER_H_
#include <string>
#include <memory>
#include <fstream>
#include "active.h"
#include "g2log.h"
/** The actual background worker, while LogWorker gives the
* asynchronous API to put job in the background the PrivateLogWorker
* does the actual background thread work */
struct PrivateLogWorker
{
PrivateLogWorker(const std::string& log_prefix, const std::string& log_directory);
~PrivateLogWorker();
void backgroundFileWrite(g2::internal::LogEntry message);
std::string log_file_with_path_;
std::unique_ptr<kjellkod::Active> bg_;
std::ofstream out;
g2::internal::time_point start_time_;
private:
PrivateLogWorker& operator=(const PrivateLogWorker&) = delete; // no assignment, no copy
PrivateLogWorker(const PrivateLogWorker& other) = delete;
};
#endif

View File

@ -96,7 +96,7 @@ int main(int argc, char** argv)
}
oss.str("");
oss << "Number of values rounded to tenths of ms dumped to file: " << g_measurement_bucket_dump << std::endl;
oss << "Number of values rounted to milliseconds and put to [millisecond bucket] were dumped to file: " << g_measurement_bucket_dump << std::endl;
oss << "Format: bucket_of_ms, number_of_values_in_bucket";
std::cout << oss.str() << std::endl;