C++: confusion about accessing class data members while multithreading - c++

I have the following minimal working example in which I create a number of markov_chain objects in a vector chains and an equal number of thread objects in a vector workers, each of which executes a markov_chain class member function sample on each of the corresponding markov_chain objects. This function takes some integer (99 in the below example) and assigns it to the acceptance public data member of the markov_chain object. I then print the value of acceptance for each object in the vector.
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
class markov_chain
{
public:
unsigned int length{0}, acceptance{0};
markov_chain(unsigned int l) {length=l;}
~markov_chain() {}
void sample(int acc);
};
void markov_chain::sample(int acc)
{
acceptance = acc;
std::cout << length << ' ' << acceptance << std::endl;
}
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
for (int i = 0; i <= number_of_threads; i++) {
chains.push_back(markov_chain(number_of_samples));
workers.push_back(std::thread(&markov_chain::sample, chains[i], 99));
}
std::for_each(workers.begin(), workers.end(), [](std::thread &t)
{
t.join();
});
for (int i = 0; i <= number_of_threads; i++) {
std::cout << chains[i].length << ' ' << chains[i].acceptance << std::endl;
}
return 0;
}
Upon executing, the program outputs
1000 99
1000 99
1000 99
1000 99
1000 0
1000 0
1000 0
1000 0
So the program failed to change the value of acceptance for the objects in the vector chains. I don't know why this happens; the function sample successfully assigns the desired value when I use it without creating threads.

There are 2 problems with your code:
when creating each std::thread, you are passing a copy of each object as the this parameter of sample().
Pushing multiple objects into the chains vector the way you are doing may cause the vector to re-allocate its internal array, thus invaliding any object pointers you have already passed to existing threads, since those original objects are now gone after the re-allocation.
You need to fully initialize the chains vector before creating any of the threads. And you need to pass a pointer to each object to each thread.
You can reserve() the array up front to avoid re-allocation while pushing into it, eg:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
chains.reserve(number_of_threads);
for (int i = 0; i < number_of_threads; ++i) {
chains.push_back(markov_chain(number_of_samples));
workers.push_back(std::thread(&markov_chain::sample, &chains[i], 99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
Demo
However, since all of the objects are being initialized with the same starting value, an easier way is to simply get rid of chains.push_back() altogether and use chains.resize() instead, eg:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
chains.resize(number_of_threads, markov_chain(number_of_samples));
for (int i = 0; i < number_of_threads; ++i) {
workers.push_back(std::thread(&markov_chain::sample, &chains[i], 99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
Demo
Or, even use the vector constructor itself:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains(number_of_threads, markov_chain(number_of_samples));
std::vector<std::thread> workers;
for (int i = 0; i < number_of_threads; ++i) {
workers.push_back(std::thread(&markov_chain::sample, &chains[i], 99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
Demo

Related

How to delay Destructor call in a loop

// Online C++ compiler to run C++ program online
#include <iostream>
#include <iterator>
#include <set>
int index;
int member[5] = {0,1,2,3,4};
class Animal{
public:
Animal(int val){
member[val]=-1;
}
~Animal(){
member[index]=index;
}
};
int main() {
// Write C++ code here
for(int i=0;i<5;i++){
std::cout<<member[i]<<" ";
}
std::cout<<std::endl;
for(int i=0;i<5;i++){
index=i;
Animal a(i);
}
for(int i=0;i<5;i++){
std::cout<<member[i]<<" ";
}
return 0;
}
In following code the output is:
0 1 2 3 4
0 1 2 3 4
But I am interested in the following output:
0 1 2 3 4
-1 -1 -1 -1 -1
So every time we perform Animal a(i); its constructor gets called and member[val]=-1 but immediately after its iteration the destructor gets called which makes the value back to val. member[index]=index.
How can we delay the call to destructor in this case?
I want the member[5]={-1,-1,-1,-,1,-1} after the for loop ends
and member[5]={0,1,2,3,4} restored to original value only when main() exists.
While it's an ugly hack, how about using a vector that gets destructed after the code you're interested in?
Perhaps something like:
{
std::vector<Animal> animals;
for(int i = 0; i < 5; ++i){
std::cout << member[i] << ' ';
}
std::cout << '\n';
for(int i = 0; i < 5; ++i){
animals.emplace_back(i);
}
for(int i = 0; i < 5; ++i){
std::cout << member[i] << ' ';
}
std::cout << '\n';
// Here the vector object life-time ends
// All Animal object will be destructed
}
As noted, this solution will use the last value of index when the Animal object are being destructed, and since it's never used by the above code it will stay at its (implicitly) initialized value of 0.
You need to store the "index" passed to the constructor in an actual member variable, and use it in the destructor:
class Animal
{
public:
Animal(int index)
: my_index{ index }
{
}
~Animal()
{
member[my_index] = my_index;
}
private:
int my_index;
};
After this you can remove the global index variable, as it's no longer used or needed.

Using vector::data() chaining with member function print differnet values as pointer arithmetic

I have a class hello with a method which returns a vector member.
I am trying to print out values using vector::data() with pointer arithmetic, but I am facing an undefined behavior. See example below:
class hello
{
public:
std::vector<int> data()
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
int main(int argc, const char **argv)
{
hello h;
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
int *sa = h.data().data();
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
return 0;
}
The result looks like this:
----------------------------
0x9e2ee0
1
0x9e2ee4
2
0x9e2ee8
3
0x9e2eec
4
----------------------------
0x9e2ee0
0
0x9e2ee4
0
0x9e2ee8
10289168
0x9e2eec
0
Why do *(sa + i) and *(h.data().data() + i) print different values?
sa + i and &*(h.data().data() + i) prints the same memory address, why I can not get the correct data just use this memory address (sa + i)
hello::data() is returning a vector by value, which means it will return a temporary copy of hello::v, which will allocate its own int array and copy the values from v.
When calling h.data(), that temporary vector will be destroyed when it goes out of scope at the end of the full statement that called h.data().
So, in your 1st loop:
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
This is perfectly valid code, as the temporary vector returned by each call to h.data() will not be destroyed until after its inner data has been printed.
However, in your 2nd loop:
int *sa = h.data().data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
In the statement that is calling h.data():
int *sa = h.data().data();
The temporary vector gets destroyed when it goes out of scope at the end of the statement, leaving sa to be a dangling pointer to freed memory, thus any use of sa inside the loop is undefined behavior.
sa + i and h.data().data() + i may point at the same memory address, but only if this last call to h.data() happens to create a new vector that reuses the same memory block that the temporary vectors in the 1st loop used, but that is not a guarantee. In any case, sa is pointing at freed memory, so it doesn't matter if the memory block was reused or not, the vector that owned that memory block is destroyed, freeing the memory, before the 2nd loop is entered. That is why you can't access the data, even if the memory addresses were the same.
To fix this issue, you need to change hello::data() to return a reference to hello::v instead, then no copy will be created, eg:
class hello
{
public:
std::vector<int>& data() // <-- note the &
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
Thus each call to h.data().data() will return a valid pointer to v's internal data, thus sa will not be a dangling pointer anymore.
Alternatively, have hello::data() return a pointer to v's data, rather than returning (a reference to) v itself, eg:
class hello
{
public:
int* data()
{
return v.data();
}
private:
std::vector<int> v{1, 2, 3, 4};
};
...
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data() + i) << std::endl;
std::cout << *(h.data() + i) << std::endl;
}
...
int *sa = h.data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
You returned a temporary copy of your vector. After the statement it is part of it is destroyed. If you wanted to keep it around you need to assign it to another vector.
So, you made a pointer to a temporary value which got erased. It no longer exists, and you're trying to point to pieces of its corpse.

How to get the correct thread id and value

I am trying to send vector as data to pthread. But when I am trying to print the thread id , its coming garbage value.
If I run this code with single thread, it works fine. But when I run it with 2 threads, its not working.
#include <iostream>
#include <pthread.h>
#include <vector>
using namespace std;
struct val {
int data;
int sData;
};
void *foo(void *a)
{
vector <val>* b = (vector <val>*)a;
for (val it : *b) {
std::cout <<" thread " <<it.data;
std::cout <<" &&& " <<it.sData<<"-----------"<<endl;
}
}
int main()
{
pthread_t thr[2];
for (int j = 0; j < 2; j++) {
std::vector <val> *a = new std::vector<val>(10);
for (int i = 0; i< 10; i++) {
val t;
t.data = j;
t.sData = j*10;
a->push_back(t);
}
pthread_create(&thr[j], NULL, &foo, &a);
}
pthread_join(thr[0],NULL);
pthread_join(thr[1],NULL);
return 0;
}
Expected Output:
thread 0 &&& 0
....
....
thread 1 &&& 10
thread 1 &&& 10
....
....
You are giving the thread a pointer to a local variable. That variable is destroyed immediately afterwards, at the closing brace of the loop. foo ends up accessing a dangling pointer, whereupon your program exhibits undefined behavior.

Crash on vector pop_back() of only remaining entry

Code:
#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>
struct myClass {
bool bIsDead;
myClass(bool bDead) {
this->bIsDead = bDead;
}
};
void PrintVector(std::vector<myClass*> vec) {
std::cout << "The vector contains: ";
for(int i = 0; i < vec.size(); i++) {
std::cout << vec[i]->bIsDead << " ";
}
std::cout << std::endl;
}
int main() {
std::srand(std::time(0)); // use current time as seed for rng
std::vector<myClass*> myVector;
for(int i = 0; i < 10; i++) {
int tempRand = std::rand() % 2;
// int tempRand = 1;
if(tempRand == 1) {
myVector.push_back(new myClass(true));
}
else {
myVector.push_back(new myClass(false));
}
}
std::cout << "Unsorted: " << std::endl;
PrintVector(myVector);
std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
{
return lhs->bIsDead < rhs->bIsDead;
});
std::cout << "Sorted: " << std::endl;
PrintVector(myVector);
while(myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
std::cout << "Removed Dead Ones: " << std::endl;
PrintVector(myVector);
return 0;
}
Output for random inputs:
Unsorted:
The vector contains: 0 0 1 0 0 0 1 1 0 1
Sorted:
The vector contains: 0 0 0 0 0 0 1 1 1 1
Removed Dead Ones:
The vector contains: 0 0 0 0 0 0
Hit ENTER to continue...
Output for all 1's (i.e. pop_back removes all):
Unsorted:
The vector contains: 1 1 1 1 1 1 1 1 1 1
Sorted:
The vector contains: 1 1 1 1 1 1 1 1 1 1
Hit ENTER to continue...
For this console application I'm not given any errors or crash warnings, but it isn't outputting the two cout statements after the pop_back call for the all 1's case.
Any ideas on why popping a vector of pointers back to empty causes the program to crash?
You need to add a check for size of vector. It shouldn't be 0 if you want to access the vector's last element using back().
Change this:
while(myVector.back()->bIsDead) {
to:
while(myVector.size() > 0 && myVector.back()->bIsDead) {
Here's the correct code:
#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>
struct myClass {
bool bIsDead;
myClass(bool bDead) {
this->bIsDead = bDead;
}
};
void PrintVector(std::vector<myClass*> vec) {
std::cout << "The vector contains: ";
for(int i = 0; i < vec.size(); i++) {
std::cout << vec[i]->bIsDead << " ";
}
std::cout << std::endl;
}
int main() {
std::srand(std::time(0)); // use current time as seed for rng
std::vector<myClass*> myVector;
for(int i = 0; i < 10; i++) {
int tempRand = std::rand() % 2;
// int tempRand = 1;
if(tempRand == 1) {
myVector.push_back(new myClass(true));
}
else {
myVector.push_back(new myClass(false));
}
}
std::cout << "Unsorted: " << std::endl;
PrintVector(myVector);
std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
{
return lhs->bIsDead < rhs->bIsDead;
});
std::cout << "Sorted: " << std::endl;
PrintVector(myVector);
while(myVector.size() > 0 && myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
std::cout << "Removed Dead Ones: " << std::endl;
PrintVector(myVector);
return 0;
}
Quoting cppreference
Calling this function(back()) on an empty container causes undefined
behavior.
PS: You don't need to make the question look so intimidating to grab our attention.
As with most problems I have, it was something simple. Thanks to billz and juanchopanza's comments it was pointed out to me that it wasn't the pop_back() that was crashing, but rather the subsequent back() called in the while loop.
This is easily fixable in several ways, 2 examples being:
adding if(myVector.empty) {break;} into the delete's while loop
or like user3286661 said, adding a conditional to the while loop first checking if it has an element.
The problem is that you try to access myVector.back() even when the vector is already empty.
The least intrusive solution (minimal modification to your code) I can think of would this:
while (!myVector.empty() && myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
The "right" thing to do would be to use either std::vector<myClass> or std::vector<std::unique_ptr<myClass>> (no need for manual delete) and use the erase-remove-idiom:
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(),
[](const auto& p) {
return p->bIsDead; //p.bIsDead for std::vector<myClass>
}
),
myVector.end()
);
This might look more complicated, but it is safer (no accidental memory leaks), probably more efficient and makes the call to sort unnecessary.

How to create a certain number of threads based on a value a variable contains?

I have a integer variable, that contains the number of threads to execute. Lets call it myThreadVar. I want to execute myThreadVar threads, and cannot think of any way to do it, without a ton of if statements. Is there any way I can create myThreadVar threads, no matter what myThreadVar is?
I was thinking:
for (int i = 0; i < myThreadVar; ++i) { std::thread t_i(myFunc); }, but that obviously won't work.
Thanks in advance!
Make an array or vector of threads, put the threads in, and then if you want to wait for them to finish have a second loop go over your collection and join them all:
std::vector<std::thread> myThreads;
myThreads.reserve(myThreadVar);
for (int i = 0; i < myThreadVar; ++i)
{
myThreads.push_back(std::thread(myFunc));
}
While other answers use vector::push_back(), I prefer vector::emplace_back(). Possibly more efficient. Also use vector::reserve(). See it live here.
#include <thread>
#include <vector>
void func() {}
int main() {
int num = 3;
std::vector<std::thread> vec;
vec.reserve(num);
for (auto i = 0; i < num; ++i) {
vec.emplace_back(func);
}
for (auto& t : vec) t.join();
}
So, obvious the best solution is not to wait previous thread to done. You need to run all of them in parallel.
In this case you can use vector class to store all of instances and after that make join to all of them.
Take a look at my example.
#include <thread>
#include <vector>
void myFunc() {
/* Some code */
}
int main()
{
int myThreadVar = 50;
std::vector <thread> threadsToJoin;
threadsToJoin.resize(myThreadVar);
for (int i = 0; i < myThreadVar; ++i) {
threadsToJoin[i] = std::thread(myFunc);
}
for (int i = 0; i < threadsToJoin.size(); i++) {
threadsToJoin[i].join();
}
}
#include <iostream>
#include <thread>
void myFunc(int n) {
std::cout << "myFunc " << n << std::endl;
}
int main(int argc, char *argv[]) {
int myThreadVar = 5;
for (int i = 0; i < myThreadVar; ++i) {
std::cout << "Launching " << i << std::endl;
std::thread t_i(myFunc,i);
t_i.detach();
}
}
g++ -std=c++11 -o 35106568 35106568.cpp
./35106568
Launching 0
myFunc 0
Launching 1
myFunc 1
Launching 2
myFunc 2
Launching 3
myFunc 3
Launching 4
myFunc 4
You need to store the thread so you can send it to join.
std::thread t[myThreadVar];
for (int i = 0; i < myThreadVar; ++i) { t[i] = std::thread(myFunc); }//Start all threads
for (int i = 0; i < myThreadVar; ++i) {t[i].join;}//Wait for all threads to finish
I think this is valid syntax, but I'm more used to c so I am unsure if I initialized the array correctly.