Pipeline with thread vectors and queues C++ - c++

here is my code, it works but after few iterations it stop without any error, probably because of some race or deadlock.
The goal of the code is to model an encoding application: after the creation of some fake random frames, the stages of my pipeline are first give the type to the frames and than encode it with some random operation.
To do that I've used two different thread vectors (one for each stage) that are used concurrently with some shared queues, once one thread have pushed a frame, it is popped by another in the other vector and "encoded".
#include <iostream>
#include <vector>
#include <algorithm>
#include "SafeQueue.h"
using namespace std;
const int DATA_MAG = 256;
struct Frame
{
int num;
char type;
bool encoded;
vector<vector<int>> grid;
};
void do_join(thread& t)
{
t.join();
}
void join_all(vector<thread>& v)
{
for_each(v.begin(),v.end(),do_join);
}
void create_input (Queue<Frame>& stream, int num_frames, int height, int width)
{
for (int i = 0; i < num_frames; i++)
{
vector<vector<int>>tmp_grid(height, vector<int>(width, 0));
Frame frame;
for (int j = 0; j < height; j++)
{
for (int k = 0; k < width; k++)
{
tmp_grid[j][k] = rand()%DATA_MAG;
}
}
frame.grid = tmp_grid;
frame.num = i;
stream.push(frame);
}
}
void decide_type(int preset, Queue<Frame>& stream, Queue<Frame>& typed, vector<char>& param, int num_frames)
{
cout<<"hello from decide"<<" "<<endl;
for(int i = 0; i < num_frames; i++)
{
Frame tmp = stream.pop();
int j = rand() % 10;
if(j < preset)
{
tmp.type = 'I';
}
else
{
tmp.type = 'B';
}
param[tmp.num] = tmp.type;
typed.push(tmp);
}
}
void decode_flow(int preset, Queue<Frame>& typed, vector<Frame>& encoded,
vector<char>& parameters, int num_frames, int height, int width)
{
cout<<"hello from decode"<<" "<<endl;
for(int i = 0; i < num_frames; i++)
{
Frame f = typed.pop();
if (f.type == 'I')
{
cout<<"hi from I"<<" "<<endl;
for (int j = 0; j < height; j++)
{
for (int k = 0; k < width; k++)
{
f.grid[j][k] = f.grid[j][k] * 2;
}
}
}
else cout<<"hi from B"<<" "<<endl;
encoded.push_back(f);
}
}
int main()
{
srand(time(NULL));
int num_threadsXstage = 2;
int width = 500;
int height = 500;
int num_frames = 100;
int frames_thread = num_frames/num_threadsXstage;
int preset = 3;
vector<Frame> final;
//Vectors of threads
vector<thread> typer;
vector<thread> encoder;
//Vector of parameters
vector<char> parameters(num_frames);
//Working queues
Queue<Frame> created;
Queue<Frame> typed;
//Final vector
vector<Frame> encoded(num_frames);
//Movie creation
create_input(created, num_frames, height, width);
for (int i = 0; i < num_threadsXstage; i++)
{
//stage 1
typer.push_back(thread(bind(&decide_type, preset, ref(created),
ref(typed), ref(parameters), frames_thread)));
//stage 2
encoder.push_back(thread(bind(&decode_flow, preset, ref(typed), ref(encoded),
ref(parameters), frames_thread, height, width)));
}
// JOIN
join_all(typer);
join_all(encoder);
for (int i = 0; i < num_frames; i++)
{
Frame k = typed.pop();
cout<<k.type<<" ";
}
cout<<endl<<endl;
for (int i = 0; i < num_frames; i++)
{
cout<<parameters[i]<<" ";
}
}
And this is the code of my thread safe queue, or at least it is supposed to be.
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
private:
queue<T> queue_;
mutex mutex_;
condition_variable cond_;
public:
T pop()
{
unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
auto val = queue_.front();
queue_.pop();
return val;
}
void pop(T& item)
{
unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
item = queue_.front();
queue_.pop();
}
void push(const T& item)
{
unique_lock<std::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock();
cond_.notify_one();
}
Queue()=default;
Queue(const Queue&) = delete; // disable copying
Queue& operator=(const Queue&) = delete; // disable assignment
};

After all threads have finished, you extract all the queued frames from the typed queue - but this is the intermediate queue between the processing stages, and is now empty. The call to typed.pop() will block forever.
You should be extracting the frames from the output queue encoded.

Related

How to synchronize data between threads

This is my class to print data
class PrintData
{
int data[20];
public:
void setData(int dataValue[])
{
for( int i = 0 ; i < 20; i++)
data[i] = dataValue[i];
}
void Print()
{
for (int i = 0; i < 20; i++)
std::cout << data[i];
std::cout << std::endl;
}
};
This is the main function
int number[20] ;
void updateNumber()
{
for (int i = 0; i < 1000; i++) {
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
for (int k = 0; k < 20; k++)
number[k] = k;
// after one iteration it should wait and after the print.Print() is executed than it should again update the data
}
}
int main()
{
PrintData print;
std::thread t(&updateNumber);
while (true)
{
// if upDateNumber has updated all the numbers than only than only set the number
print.setData(number);
print.Print();
}
return 0;
}
After iteration has finished in the thread it should wait for the print.setData(number) function to execute , once this function has executed it should again update the data.
if print.setData(number) is called and the thread is still not finished updating the array than print.setData(number) should not update the data.
A simple example of a producer consumer problem involving conditional variables would be something like that:
#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>
#include <vector>
#include <unistd.h>
#define MAX_SIZE 2
struct Task
{
std::condition_variable m_cond;
std::mutex m_lock;
Task(){}
};
std::vector<int> m_data;
Task m_producer;
Task m_consumers[MAX_SIZE];
std::mutex m_lock;
static bool s_Busy = false;
static void producer(void)
{
for(;;)
{
size_t input=0;
std::unique_lock<std::mutex> lock{m_lock};//{m_producer.m_lock};
if (!s_Busy) {
std::cout << "Enter a number: ";
std::cin >> input;
std::cout << "Producer waiting..." << std::this_thread::get_id() << "\r\n";
m_producer.m_cond.wait(lock);
}
s_Busy = true;
if (m_data.size() < input) {
for (size_t i=0; i < input; ++i){
m_data.push_back(i);
}
}
for (int i=0; i < MAX_SIZE; ++i) {
m_consumers[i].m_cond.notify_one();
}
lock.unlock();
}
}
static void consumers(void)
{
for(;;)
{
std::unique_lock<std::mutex> lock{m_lock};
if (!s_Busy) {
std::cout <<"Consumers waiting....!" << std::this_thread::get_id() << "\r\n";
for (int i=0; i < MAX_SIZE; ++i) {
m_consumers[i].m_cond.notify_all();
}
}
if (!m_data.empty()) {
std::cout << "Remove: " << m_data.at(0) << std::endl;
m_data.erase(m_data.begin());
usleep(1);
}
s_Busy = false;
m_producer.m_cond.notify_one();
lock.unlock();
}
}
int main()
{
std::vector<std::thread> cnsmrs;
std::thread usr{producer};
for (int i=0; i < MAX_SIZE; ++i)
cnsmrs.push_back(std::thread{consumers});
usr.join();
for(int i=0 ; i < MAX_SIZE; ++i)
cnsmrs.at(i).join();
return 0;
}
You can play with different logic and implementation.
I hope this help you: (semaphore is a self implementation of Qt's QSemaphore)
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
class semaphore
{
public:
semaphore(int n = 0) : m_n(n)
{
}
public:
void acquire(int n = 1)
{
std::unique_lock <std::mutex> lk(m_buf_mut);
while (m_n < n) {
m_cv.wait(lk);
}
m_n -= n;
}
void release(int n = 1)
{
{
std::unique_lock <std::mutex> lk(m_buf_mut);
m_n += n;
}
m_cv.notify_all();
}
bool tryAcquire(int n = 1)
{
std::unique_lock <std::mutex> lk(m_buf_mut);
if (m_n >= n) {
m_n -= n;
return true;
}
return false;
}
private:
std::mutex m_buf_mut;
int m_n;
std::condition_variable m_cv;
};
class PrintData
{
int data[20];
public:
void setData(int dataValue[])
{
for( int i = 0 ; i < 20; i++)
data[i] = dataValue[i];
}
void Print()
{
for (int i = 0; i < 20; i++)
std::cout << data[i];
std::cout << std::endl;
}
};
int number[20] ;
void updateNumber(semaphore *freeSem, semaphore *usedSem)
{
for (int i = 0; i < 1000; i++) {
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
//
freeSem->acquire();
for (int k = 0; k < 20; k++)
number[k] = k;
usedSem->release();
// after one iteration it should wait and after the print.Print() is executed than it should again update the data
}
}
int main()
{
PrintData print;
semaphore freeSem(1);
semaphore usedSem(0);
std::thread t(&updateNumber, &freeSem, &usedSem);
while (true)
{
// if upDateNumber has updated all the numbers than only than only set the number
usedSem.acquire();
print.setData(number);
print.Print();
freeSem.release();
}
return 0;
}

Adding threads increases time needed to perform the same task

I have been struggling with this for past 3 days. I do some stuff in image processing. I came to a point where I could distribute the workflow to more threads since I had "patches" of image, that I could pass to different threads. Unfortunately, the whole time it took to process the image was the same no matter if using 1 or more threads.
So I started digging, making copies of patches so every thread has its own local data, stopped writing result to array, but it was still the same. So I made the most minimalistic program I could have. After thread was created, it would make 10x10 matrix and write its determinant to console. So nothing shared between, only thing passed was index of a thread.
But it was still the same. I made tests both on Linux and Windows. These show time required to compute one determinant, so when using two threads each one took the same amount of time if not stated otherwise:
Windows:
1 Thread = 4479ms
2 Threads = 7500ms
3 Threads = 11300ms
4 Threads = 15800 ms
Linux:
1 Thread = 490ms
2 Threads = 478ms
3 Threads = First: 503ms; Other two: 1230ms
4 Threads = 1340ms
first thing is obvious, Linux is computing the same thing 10x faster. Nevermind. However windows not that single thread performance is worse, it gets worse no matter how many I add. Linux seems to be slowed down only when workload is being done on logical core. Thats why 1 and 2 are ok, since I have 2Core with HT, and when using 3 threads it slows down on the core that uses HT as well but the other is ok. However windows sucks no matter what.
Funny thing is that on windows it takes +- the same amount of time if I compute 4 determinants on one core or 1 determinant on each core.
The code I was using to get these results. I was able to compile with g++ and msvc no problem. Important are only last few methods, there are some constructors I wasn't sure are not being used.
#include <iostream>
#include <cmath>
#include <thread>
#include <chrono>
#include <float.h>
class FVector
{
public:
FVector();
FVector(int length);
FVector(const FVector &vec);
FVector(FVector &&vec);
FVector &operator=(const FVector &vec);
FVector &operator=(FVector &&vec);
~FVector();
void setLength(int length);
int getLength() const;
double *getData();
const double* getConstData() const;
private:
double *data;
int length;
void allocateDataArray(int length);
void deallocateDataArray();
};
FVector::FVector() {
data = nullptr;
length = 0;
}
FVector::FVector(int length) {
data = nullptr;
this->length = length;
allocateDataArray(length);
for (int i = 0; i < length; i++) {
data[i] = 0.;
}
}
FVector::FVector(const FVector &vec) {
allocateDataArray(vec.length);
length = vec.length;
for (int i = 0; i < length; i++) {
data[i] = vec.data[i];
}
}
FVector::FVector(FVector &&vec) {
data = vec.data;
vec.data = nullptr;
length = vec.length;
}
FVector &FVector::operator=(const FVector &vec) {
deallocateDataArray();
if (data == nullptr) {
allocateDataArray(vec.length);
for (int i = 0; i < vec.length; i++) {
data[i] = vec.data[i];
}
length = vec.length;
}
return *this;
}
FVector &FVector::operator=(FVector &&vec) {
deallocateDataArray();
if (data == nullptr) {
data = vec.data;
vec.data = nullptr;
length = vec.length;
}
return *this;
}
FVector::~FVector() {
deallocateDataArray();
}
void FVector::allocateDataArray(int length) {
data = new double[length];
}
void FVector::deallocateDataArray() {
if (data != nullptr) {
delete[] data;
}
data = nullptr;
}
int FVector::getLength() const {
return length;
}
double *FVector::getData() {
return data;
}
void FVector::setLength(int length) {
deallocateDataArray();
allocateDataArray(length);
this->length = length;
}
const double* FVector::getConstData() const {
return data;
}
class FMatrix
{
public:
FMatrix();
FMatrix(int columns, int rows);
FMatrix(const FMatrix &mat);
FMatrix(FMatrix &&mat);
FMatrix& operator=(const FMatrix &mat);
FMatrix& operator=(FMatrix &&mat);
~FMatrix();
FVector *getData();
const FVector* getConstData() const;
void makeIdentity();
int determinant() const;
private:
FVector *data;
int columns;
int rows;
void deallocateDataArray();
void allocateDataArray(int count);
};
FMatrix::FMatrix() {
data = nullptr;
columns = 0;
rows = 0;
}
FMatrix::FMatrix(int columns, int rows) {
data = nullptr;
allocateDataArray(columns);
for (int i = 0; i < columns; i++) {
data[i].setLength(rows);
}
this->columns = columns;
this->rows = rows;
}
FMatrix::FMatrix(const FMatrix &mat) {
data = nullptr;
allocateDataArray(mat.columns);
for (int i = 0; i < mat.columns; i++) {
data[i].setLength(mat.data[i].getLength());
data[i] = mat.data[i];
}
columns = mat.columns;
rows = mat.rows;
}
FMatrix::FMatrix(FMatrix &&mat) {
data = mat.data;
mat.data = nullptr;
columns = mat.columns;
rows = mat.rows;
}
FMatrix &FMatrix::operator=(const FMatrix &mat) {
deallocateDataArray();
if (data == nullptr) {
allocateDataArray(mat.columns);
for (int i = 0; i < mat.columns; i++) {
data[i].setLength(mat.rows);
data[i] = mat.data[i];
}
}
columns = mat.columns;
rows = mat.rows;
return *this;
}
FMatrix &FMatrix::operator=(FMatrix &&mat) {
deallocateDataArray();
data = mat.data;
mat.data = nullptr;
columns = mat.columns;
rows = mat.rows;
return *this;
}
FMatrix::~FMatrix() {
deallocateDataArray();
}
void FMatrix::deallocateDataArray() {
if (data != nullptr) {
delete[] data;
}
data = nullptr;
}
void FMatrix::allocateDataArray(int count) {
data = new FVector[count];
}
FVector *FMatrix::getData() {
return data;
}
void FMatrix::makeIdentity() {
for (int i = 0; i < columns; i++) {
for (int j = 0; j < rows; j++) {
if (i == j) {
data[i].getData()[j] = 1.;
}
else {
data[i].getData()[j] = 0.;
}
}
}
}
int FMatrix::determinant() const {
int det = 0;
FMatrix subMatrix(columns - 1, rows - 1);
int subi;
if (columns == rows && rows == 1) {
return data[0].getData()[0];
}
if (columns != rows) {
//throw EXCEPTIONS::SINGULAR_MATRIX;
}
if (columns == 2)
return ((data[0].getConstData()[0] * data[1].getConstData()[1]) - (data[1].getConstData()[0] * data[0].getConstData()[1]));
else {
for (int x = 0; x < columns; x++) {
subi = 0;
for (int i = 0; i < columns; i++) {
for (int j = 1; j < columns; j++) {
if (x == i) {
continue;
}
subMatrix.data[subi].getData()[j - 1] = data[i].getConstData()[j];
}
if (x != i) {
subi++;
}
}
det += (pow(-1, x) * data[x].getConstData()[0] * subMatrix.determinant());
}
}
return det;
}
const FVector* FMatrix::getConstData() const {
return data;
}
class FCore
{
public:
FCore();
~FCore();
void process();
private:
int getMaxThreads() const;
void joinThreads(std::thread *threads, int max);
};
void parallelTest(int i) {
auto start = std::chrono::high_resolution_clock::now();
FMatrix m(10, 10);
m.makeIdentity();
std::cout << "Det: " << i << "= " << m.determinant() << std::endl;
auto finish = std::chrono::high_resolution_clock::now();
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(finish - start);
std::cout << "Time: " << microseconds.count() / 1000. << std::endl;
}
FCore::FCore()
{
}
FCore::~FCore()
{
}
void FCore::process() {
/*********************************************/
/*Set this to limit number of created threads*/
int threadCount = getMaxThreads();
/*********************************************/
/*********************************************/
std::cout << "Thread count: " << threadCount;
std::thread *threads = new std::thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = std::thread(parallelTest, i);
}
joinThreads(threads, threadCount);
delete[] threads;
getchar();
}
int FCore::getMaxThreads() const {
int count = std::thread::hardware_concurrency();
if (count == 0) {
return 1;
}
else {
return count;
}
}
void FCore::joinThreads(std::thread *threads, int max) {
for (int i = 0; i < max; i++) {
threads[i].join();
}
}
int main() {
FCore core;
core.process();
return 0;
}
Obviously I've done some testing with more primitive ones, as simple as adding numbers and it was the same. So I just wanted to ask if any of you have ever stumbled on something remotely similar to this. I know that I won't be able to get the awesome time on windows as it is on Linux, but at least the scaling could be better.
Tested on Win7/Linux intel 2C+2T and Win10 ryzen 8C+8T. Times posted are from 2C+2T

Memory leak without allocating any memory?

I'm working on a coding assignment for a C++ class. When I run my program I seem to be dealing with a memory leakage issue, which is weird since I am NOT explicitly allocating any memory in my code. I ran the program under gdb, and it seems as though the program crashes when running the destructor for a Deck object. I tried stepping through the code, but I when I do so I end up in a host of .h files related to vectors. Then suddenly, it stops. I tried going to a TA for some help, but they seem to be as perplexed as I am on the issue.
# include <stdlib.h>
# include <time.h>
# include <iostream>
# include <vector>
# include <stdio.h>
using namespace std;
//function signatures
float bustProbability (const int);
class Deck
{
public:
//data members
vector <int> cardArray;
vector <int> wasteCards;
//constructor
Deck();
//methods
void shuffleDeck();
void populateDeckWithCards();
void removeCopyCards();
int dealCard();
int remainingCards();
void showCards();
};
void Deck::removeCopyCards() {
for (unsigned int i = 0; i < wasteCards.size(); i++) {
bool removedCopy = false;
for (unsigned int j = 0; j < cardArray.size() && removedCopy == false; j++) {
if (cardArray[j] == wasteCards[i]) {
cardArray.erase (cardArray.begin() + j - 1);
removedCopy = true;
}
}
}
}
int Deck::dealCard() {
if (remainingCards() > 0) {
int tmp = cardArray.back();
wasteCards.push_back(tmp);
cardArray.pop_back();
return tmp;
}
else {
populateDeckWithCards();
removeCopyCards();
shuffleDeck();
//shuffle method
int tmp = cardArray.back();
cardArray.pop_back();
return tmp;
}
}
void Deck::populateDeckWithCards() {
//populate regular cards into array
for (int i = 2; i <= 10; i++) {
for (int j = 0; j < 4; j++) {
cardArray.push_back(i);
}
}
//populate J, Q, K into array
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cardArray.push_back(10);
}
}
//populating array with Aces... treating them as special case '100'
for (int i = 0; i < 4; i++) {
cardArray.push_back(100);
}
return;
}
void Deck::showCards() {
for (unsigned int i = 0; i < cardArray.size(); i++) {
cout << cardArray[i] << endl;
}
}
Deck::Deck() {
wasteCards.clear();
cardArray.clear();
populateDeckWithCards();
shuffleDeck();
}
void Deck::shuffleDeck() {
int n = cardArray.size();
for(int a = n-1; a > 0; a--) {
int min = 0;
int max = a;
int j = min + rand() / (RAND_MAX / (max-min + 1) + 1);
int tmp = cardArray[a];
cardArray[a] = cardArray[j];
cardArray[j] = tmp;
}
return;
}
int Deck::remainingCards() {
return cardArray.size();
}
class Player {
public:
//data members
vector <int> playerHand;
//constructor
Player();
//methods
bool isBust();
int count();
void hit(Deck&);
void stand();
bool muckHand();
void showHand();
};
Player::Player() {
playerHand.clear();
}
void Player::showHand() {
for (unsigned int i = 0; i < playerHand.size(); i++) {
cout << playerHand[i] << endl;
}
return;
}
int Player::count() {
int handCount = 0;
for (unsigned int i = 0; i < playerHand.size(); i++) {
if (playerHand[i] != 100)
handCount += playerHand[i];
else {
if (playerHand[i] == 100) {
if ((handCount) > 11) {
handCount += 1;
}
else
handCount += 10;
}
}
}
return handCount;
}
bool Player::isBust() {
if (count() > 21)
return true;
else
return false;
}
void Player::hit(Deck& d) {
playerHand.push_back(d.dealCard());
}
void Player::stand() {
return;
}
bool Player::muckHand() {
playerHand.clear();
return true;
}
float bustProbability (const int threshHold) {
int threshHoldReached = 0;
Deck myDeck;
Player myPlayer;
Player dealer;
for (int i = 0; i < 10000; i++) {
myPlayer.hit(myDeck);
dealer.hit(myDeck);
myPlayer.hit(myDeck);
dealer.hit(myDeck);
while (myPlayer.count() < threshHold) {
myPlayer.hit(myDeck);
}
if (!(myPlayer.isBust())) {
++threshHoldReached;
}
myDeck.wasteCards.clear();
myPlayer.muckHand();
dealer.muckHand();
}
float bustFraction = float(threshHoldReached)/float(10000);
return bustFraction;
}
int main () {
cout << "blackjack simulation" << endl;
srand((unsigned int)time(NULL));
cout << bustProbability(19);
return 0;
}
I'm incredibly sorry for just posting my code, but I've spend 4 days on this issue, and I can't even begin to figure out what the problem is.
There is at least the line
cardArray.erase (cardArray.begin() + j - 1);
which seems to be dubious in case of j = 0

Boost returning values from multithread vector

I am trying to develop a code which generates N threads into a loop. Each thread generates 40 random numbers and pick from them the highest. Afterwards, I have to choose the highest number from all. However, when I return the highest value of each thread (b) it is empty, this is the code I am using:
class rdm_thr
{
public:
rdm_thr()
{
}
void rdmgen()
{
default_random_engine generator;
double rdm;
b=0;
normal_distribution<double> normal(0, 1);
for(int i=0; i<40; i++)
{
rdm = normal(generator);
if(rdm>b)
b = rdm;
}
}
};
void main()
{
vector<boost::thread *> z;
vector<rdm_thr> o;
boost::function<void()> th_func;
for (int i = 0; i < 2; i++)
o.push_back(rdm_thr());
for (int i = 0; i < 2; i++)
{
th_func = boost::bind(&rdm_thr::rdmgen, &o[i]);
boost::thread thr(th_func);
z.push_back(&thr);
}
for (int i = 0; i < 2; i++)
{
z[i]->join();
}
}
Is there another way to do it?
You could change your class logic as such:
class rdm_thr
{
public:
rdm_thr() {}
void rdmgen()
{
...
}
void join() { t.join(); }
void start()
{
t = boost::thread(boost::bind(&rdm_thr::rdmgen, this));
}
private:
boost::thread t;
// could also be pointer type and 'new/delete' would have to be used in that event
};
#define TSZ 2
void main()
{
std::vector<rdm_thr*> o;
int i = 0;
for (; i < TSZ; i++) {
o.push_back(new rdm_thr());
o.back()->start();
}
for (i = 0; i < TSZ; i++) {
o[i]->join();
delete o[i]; //clean up
}
}
And if you didn't want to change your class logic, you could do the following in your main function:
#define TSZ 2
void main()
{
std::vector<boost::thread *> z;
std::vector<rdm_thr *> o;
int i = 0;
for (; i < TSZ; i++) {
o.push_back(new rdm_thr());
z.push_back(new boost::thread(boost::bind(&rdm_thr::rdmgen, o.back())));
}
for (i = 0; i < TSZ; i++) {
z[i]->join();
delete z[i];
delete o[i];
}
}
I don't have access to a compiler right now so I can't verify 100%, but as your asking more on theory, the above code is to help illustrate alternative ways of achieving similar results.
I hope that can help

2D vector class variable for a genetic algorithm gives a bad_alloc error

I'm writing a genetic algorithm for which I'm creating a "crossover" operator as a class object that is passed the two parent "chromosomes" Because the input and therefore the output chromosomes are variable lengths, my idea was two divide the input chromosomes and place in a sort of storage class variable, then resize the input chromosomes, and then finally refill the input chromosomes. I'm getting a bad_alloc error, however. If someone could spot my error I'd very much appreciate the help.
Thanks! My class code is below. Note that "plan_vector" is a 2d vector of int types.
#include <iostream>
#include <vector>
#include <eo>
class wetland_vector : public std::vector<int> {
public:
wetland_vector() : std::vector<int>(1, 0) {
}
};
std::istream& operator>>(std::istream& is, wetland_vector& q) {
for (unsigned int i = 0, n = 1; i < q.size(); ++i) {
is >> q[i];
}
return is;
}
std::ostream& operator<<(std::ostream& os, const wetland_vector& q) {
os << q[0];
for (unsigned int i = 1, n = 1; i < q.size(); ++i) {
os << " " << q[i];
}
os << " ";
return os;
}
class wetland_vector_Init : public eoInit<wetland_vector> {
public:
void operator()(wetland_vector& q) {
for (unsigned int i = 0, n = q.size(); i < n; ++i) {
q[i] = rng.random(10);
}
}
};
class plan_vector : public eoVector<double, wetland_vector> {
};
int read_plan_vector(plan_vector _plan_vector) {
for (unsigned i = 0; i < _plan_vector.size(); i++) {
//Call function that reads Quad[1]
//Call function that reads Quad[2]
//etc
return 0;
}
return 0;
};
class eoMutate : public eoMonOp<plan_vector> {
int subbasin_id_min;
int subbasin_id_max;
int wetland_id_min;
int wetland_id_max;
bool operator() (plan_vector& _plan_vector) {
//decide which Quad to mutate
int mutate_quad_ID = rng.random(_plan_vector.size());
//decide which Gene in Quad to mutate
int mutate_gene_ID = rng.random(_plan_vector[mutate_quad_ID].size());
//mutation procedure if first slot in the Quad is selected for mutation
if (mutate_quad_ID = 0) {
_plan_vector[mutate_quad_ID][mutate_gene_ID] = rng.random(subbasin_id_max);
}
//mutation procedure if second slot in the Quad is selected for mutation
if (mutate_quad_ID = 1) {
_plan_vector[mutate_quad_ID][mutate_gene_ID] = rng.random(subbasin_id_max);
}
//note: you'll need to add more for additional wetland characteristics
return true;
};
public:
void set_bounds(int, int, int, int);
};
void eoMutate::set_bounds(int a, int b, int c, int d) {
subbasin_id_min = a;
subbasin_id_max = b;
wetland_id_min = c;
wetland_id_max = d;
}
double evaluate(const plan_vector& _plan_vector) {
int count = 0;
for (int i = 0; i < _plan_vector.size(); i++) {
for (int j = 0; j < _plan_vector[i].size(); j++) {
count += _plan_vector[i][j];
}
}
return (count);
}
class eoQuadCross : public eoQuadOp<plan_vector> {
public:
std::string className() const {
return "eoQuadCross";
}
plan_vector a1;
plan_vector a2;
plan_vector b1;
plan_vector b2;
bool operator() (plan_vector& a, plan_vector& b) {
int cross_position_a = rng.random(a.size() - 1);
int cross_position_b = rng.random(b.size() - 1);
for (int i = 0; i < cross_position_a; i++) {
a1.push_back(a[i]);
}
for (int i = cross_position_a; i < a.size(); i++) {
a2.push_back(a[i]);
}
for (int i = 0; i < cross_position_b; i++) {
b1.push_back(b[i]);
}
for (int i = cross_position_b; i < b.size(); i++) {
b2.push_back(b[i]);
}
int size_a = b2.size() + a1.size();
int size_b = a2.size() + b1.size();
a.resize(size_a);
b.resize(size_b);
for (int i = 0; i < b2.size(); i++) {
a.push_back(b2[i]);
}
for (int i = 0; i < a1.size(); i++) {
a.push_back(a1[i]);
}
for (int i = 0; i < a2.size(); i++) {
b.push_back(a2[i]);
}
for (int i = 0; i < b1.size(); i++) {
b.push_back(b1[i]);
};
//Return bool
return true;
}
};
int main() {
unsigned int vec_size_min = 1;
unsigned int vec_size_max = 10;
unsigned int pop_size = 100;
//BEGIN COPY PARAMETRES
const unsigned int MAX_GEN = 100;
const unsigned int MIN_GEN = 5;
const unsigned int STEADY_GEN = 50;
const float P_CROSS = 0.8;
const float P_MUT = 0.5;
const double EPSILON = 0.01;
double SIGMA = 0.3;
const double uniformMutRate = 0.5;
const double detMutRate = 0.5;
const double normalMutRate = 0.5;
//END COPY PARAMETERS
rng.reseed(1);
//Create population
wetland_vector_Init atom_init;
eoInitVariableLength<plan_vector> vec_init(vec_size_min, vec_size_max, atom_init);
eoPop<plan_vector> pop(pop_size, vec_init);
//Create variation operators
eoMutate mutate;
mutate.set_bounds(1, 453, 1, 4);
eoQuadCross crossover;
eoDetTournamentSelect<plan_vector> select(3);
eoSGATransform<plan_vector> transform(crossover, .5, mutate, .2);
//Create fitness function
eoEvalFuncPtr<plan_vector> eval(evaluate);
//Evaluate initial population and cout
apply<plan_vector > (eval, pop);
std::cout << pop << std::endl;
//Set GA for execution and execute
eoGenContinue<plan_vector> GenCount(5);
eoSGA<plan_vector> gga(select, crossover, .5, mutate, .1, eval, GenCount);
gga(pop);
//cout final population and end
std::cout << pop << std::endl;
std::cout << "The End" << std::endl;
}
a1.~vector();
a2.~vector();
b1.~vector();
b2.~vector();
You shall not destruct the vectors manually, otherwise the next time you try to access them (upon next call to the operator ()) you get undefined behavior.
Why do you call vector destructor manually?? You should let C++ call that for you. If you want to clear the vector use clear member function