Passing a struct to a thread, how access multiple data in struct? - c++

I have a problem. I need to use a struct of OpenCV Mat images for passing multiple arguments to a thread.
I have a struct like this:
struct Args
{
Mat in[6];
Mat out[6];
};
And a void function called by thread, like this:
void grey (void *param){
while (TRUE)
{
WaitForSingleObject(mutex,INFINITE);
Args* arg = (Args*)param;
cvtColor(*arg->in,*arg->out,CV_BGR2GRAY);
ReleaseMutex(mutex);
_endthread();
}
}
For launch the grey function as thread with two Mat array arguments, I use the follow line in main:
Args dati;
*dati.in = *inn;
*dati.out = *ou;
handle1 = (HANDLE) _beginthread(grey,0,&dati);
Now, my problem is: I need to access to all 6 elements of two array "in" and "out" in struct passed to thread from thread itself or however, find a mode to shift array from 0 to 5 to elaborate all elements with the "grey" functions.
How can I do this from thread or from main? I mean using grey function for elaborate all 6 elements of array Mat in[6] of struct Args that I pass to thread in that mode.
Can someone help me or gime me an idea? I don't know how do this.

Before you create the thread, you assign the array like this:
*dati.in = *inn;
*dati.out = *ou;
This will only assign the first entry in the array. The rest of the array will be untouched.
You need to copy all of the source array into the destination array. You can use std::copy for this:
std::copy(std::begin(dati.in), std::end(dati.in), std::begin(inn));
Of course, that requires that the source "array" inn contains at least as many items as the destination array.
Then in the thread simply loop over the items:
for (int i = 0; i < 6; i++)
{
cvtColor(arg->in[i], arg->out[i], CV_BGR2GRAY);
}

When you launch your thread, this code:
Args dati;
*dati.in = *inn;
*dati.out = *ou;
is only initialising one of the six elements. If inn and ou are actually 6 element arrays, you will need a loop to initialise all 6.
Args dati;
for (int i = 0; i < 6; i++) {
dati.in[i] = inn[i];
dati.out[i] = ou[i];
}
Similarly, in your thread, you're only processing the first element in the array. So this code:
Args* arg = (Args*)param;
cvtColor(*arg->in,*arg->out,CV_BGR2GRAY);
would need to become something like this:
Args* arg = (Args*)param;
for (int i = 0; i < 6; i++) {
cvtColor(arg->in[i],arg->out[0],CV_BGR2GRAY);
}

Related

Adding a new instance of an array to a vector

This is a continuation of my previous question: Nested vector<float> and reference manipulation.
I got the loops and all working, but I'm trying to add new instances of arrays to a total vector.
Here's one example of what I mean:
array<float, 3> monster1 = { 10.5, 8.5, 1.0 };
// ...
vector<array<float, 3>*> pinkys = { &monster1};
// ...
void duplicateGhosts() {
int count = 0;
int i = pinkys.size(); // this line and previous avoid overflow
array<float, 3>& temp = monster1; // this gets the same data, but right now it's just a reference
for (auto monster : pinkys) { // for each array of floats in the pinkys vector,
if (count >= i) // if in this instance of duplicateGhosts they've all been pushed back,
break;
pinkys.push_back(&temp); // this is where I want to push_back a new instance of an array
count++;
}
}
With the current code, instead of creating a new monster, it is adding a reference to the original monster1 and therefore affecting its behavior.
As mentioned in a comment you cannot insert elements to a container you are iterating with a range based for loop. That is because the range based for loop stops when it reaches pinkys.end() but that iterator gets invalidated once you call pinkys.push_back(). It is not clear why you are iterating pinkys in the first place. You aren't using monster (a copy of the elements in the vector) in the loop body.
The whole purpose of the loop seems to be to have as many iterations as there are already elements in the container. For that you need not iterate elements of pinkys but you can do:
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
// add elements
}
Further, it is not clear why you are using a vector of pointers. Somebody has to own the monsters in the vector. If it isnt anybody else, it is the vector. And in that case you should use a std::vector<monster>. For shared ownership you should use std::shared_ptr. Never use owning raw pointers!
Don't use a plain array for something that you can give a better name:
struct monster {
float hitpoints; // or whatever it actually is.
float attack; // notice how this is much clearer
float defense; // than using an array?
};
With those modifications the method could look like this:
void duplicateGhosts() {
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
pinkys.push_back( pinkys[i] );
}
}
From the name of the method I assumed you want to duplciate the vectors elements. If you want to just add the same monster as many times as there were elements before, that is
void duplicateGhosts() {
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
pinkys.push_back( monster{} );
}
}

For loop in C++ stops after a single iteration w/ pointer variable

So first all I'll preface this with: I just started using c++.
I have a structure that I store the pointer to in an unordered_map, setting members' values in the struct pointer as I get them through my process. Then I no longer need them in a map so I transfer then to a vector and loop through them.
Though on the second loop, it outputs my index (1) but the next statement of making a local pointer var for the struct at that index breaks it and the code terminates without any errors. since there are no errors then a try/catch doesn't give me anything either.
// Wanted to create a structure to handle the objects easier instead
// of multiple vectors for each property
struct appData {
std::string id = "";
std::string name = "";
std::string vdf_file = "";
std::string vdf_path = "";
};
// Relevant parts of my main()
int main() {
// Map that stores all the struct pointers
std::unordered_map<std::string, appData*> appDatas;
char memory[sizeof(appData)];
void* p = memory;
// New instance of appData
appData *tempAppData = new(p) appData();
tempAppData->appid = "86901";
// Add tempAppData to map with string key
appDatas["86901"] = tempAppData;
...
std::vector<appData*> unhashed_appDatas;
for (auto const& pair: appDatas) {
unhashed_appDatas.push_back(pair.second);
}
...
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
// Output index to see where it was messing up
std::cout << x << std::endl;
!! // This is where the issue happens on the second loop (see output)
appData *thisAppData = unhashed_appDatas[x];
std::string id = thisAppData->appid;
std::cout << id << std::endl;
/* ...
Do more stuff below
*/
}
...
return 0;
}
Terminal Output:
0 // Initial index of x
86901 // Id of first item
1 // New index of x on second loop before pointer var is created
// Nothing more is printed and execution terminates with no errors
My knowledge of c++ is pretty lacking, started it couple days ago, so the few things within my knowledge I've tried: moving the *thisAppData variable outside of the loop, using a for(var: vector) { ... }, and a while loop. I can assume that the issue lies with the pointer and the local variable when inside the loop.
Any help/input about how I could better approach this or if there's an issue with my code would be appreciated :)
Edit: Changed code to use .size() instead of sizeof() per #Jarod42 answer, though main issue persists
Edit2: Turns out it was my own mess-up, imagine that. 4Am brain wasn't working too well- posted answer regarding what I did incorrectly. Thanks to everyone who helped me
sizeof is the wrong tool here:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
// ^^ wrong: give **static** size of the structure
// mainly 3 members (data, capacity, size), so something like `3*sizeof(void*)`
it should be
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
After many hours of trial and error I have determined the issue (aside from doing things in a way I should, which I've since corrected) it was something I messed up on that caused this issue.
TLDR:
Items wouldn't exist that I assumed did and tried to read files with a blank path and parse the contents that didn't exist.
Explaination:
In the first loop, the data I was getting was a list of files from a directory then parsing a json-like file that contained these file names and properties associated with them. Though, the file list contained entries that weren't in this other data file (since I had no check if they existed) so it would break there.
Additionally in the last loop I would get a member from a struct that would be the path of a file to read, but it would be blank (unset) because it didn't exist in data file so std::ifstream file(path); would break it.
I've since implemented checks for each key and value to ensure it will no longer break because of that.
Fixes:
Here are some fixes that were mentioned that I added to the code, which did help it work correctly in the end even if they weren't the main issue that I myself caused:
// Thanks to #EOF:
// No longer "using placement new on a buffer with automatic storage duration"
// (whatever that means haha) and was changed from:
char memory[sizeof(appData)];
void* p = memory;
appData *tempAppData = new(p) appData();
// To:
appData *tempAppData = new appData();
// Thanks to #Jarod42:
// Last for loop limit expression was corrected from:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
}
// To:
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
}
// I am still using a map, despite comment noting to just use vectors
// (which I could have, but just would prefer using maps):
std::unordered_map<std::string, appData*> appDatas;
// Instead of doing something like this instead (would have arguably have been easier):
std::vector<std::string> dataKeys = { "1234" };
std::vector<appData*> appDatas = { ... };
auto indx = find(dataKeys.begin(), dataKeys.end(), "1234");
indx = (indx != dataKeys.end() ? indx : -1);
if (indx == -1) continue;
auto dataItem = appDatas[indx];
//
I appreciate everyone's assistance with my code

C++ 11 thread class member function in for loop gives segmentation fault

I have 8 datasets stored as pairs in a vector and decide to pass one by one into a class and do some job with a function inside that class. Segmentation fault is generated. Here is my code:
vector<thread> threads;
for (int i = 0; i < 8; i++) { // generate 8 threads
LogOdd CEB; // create LogOdd obj
CEB.set_data(coord[i].second, coord[i].first); // pass parameters to private members
threads.push_back(thread(&LogOdd::scan, &CEB));
for (int i = 0; i < 8; i++){
threads[i].join();
}
the class looks like:
class LogOdd {
private:
string sequence;
string chromosome;
public:
void scan() { // function to be threaded
...
}
void set_data(string SEQUENCE, string CHROMOSOME) { // set parameters
sequence = SEQUENCE;
chromosome = CHROMOSOME;
}
};
I'm pretty sure the segmentation fault generated in the first threading for loop but have no idea... I know this topic might be a duplicate but I have done a lot of search already. Please help!
UPDATE
Thanks for answering my question. I edited my code in 2 ways and they work!
vector<thread> threads;
for (int i = 0; i < 8; i++) { // generate 8 threads
LogOdd * CEB = new LogOdd; // create LogOdd obj
CEB->sequence = coord[i].second;
CEB->chromosome = coord[i].first;
threads.push_back(thread(&LogOdd::scan, CEB));
}
Another way I do is storing all 8 obj into a vector first and then assign to threads:
vector<thread> threads;
vector<LogOdd> LogOddvec;
for (int i = 0; i < 8; i++) {
LogOdd CEB;
CEB.sequence = coord[i].second;
CEB.chromosome = coord[i].first;
LogOddvec.push_back(CEB);
}
for (int i = 0; i < 8; i++) {
threads.push_back(thread(&LogOdd::scandinuc, &LogOddvec[i]));
}
Lets look at these lines:
for (int i = 0; i < 8; i++) { // generate 8 threads
LogOdd CEB; // create LogOdd obj
...
threads.push_back(thread(&LogOdd::scan, &CEB));
...
}
Inside the loop you define the variable CEB. You pass a pointer to this variable to the thread. Then the loop iterates, and CEB goes out of scope and is destructed.
That means the threads are passed a pointer to a destructed object. Dereferencing that pointer in the threads will lead to undefined behavior which is a very common caues of crashes like yours.
The simplest solution is to allocate the LogOdd object dynamically with new. A possibly better solution would be to pass CEB by value to the thread functions. Another solution would be to pass coord[i].second and coord[i].first as arguments to the thread function (or possibly a constant reference to coord[i]), and have the thread function create its own LogOdd object.
I believe the problem is in LogOdd CEB. You allocate it statically inside a block, so it gets destroyed by the end of the block, which is at the end of iteration in which it has been created.
You are then using a pointer to object that no longer exists, which ends up being undefined behaviour. Easiest solution would be to use new to allocate it dynamically.

Seg Fault resulting from push_back call on vector (threads linux)

So what I'm trying to do is write a program that creates a series of child threads that take the arguments using the pthread_create method and uses the parameter passed in to do more manipulation and so on. The parameter I'm trying to pass in is a vector argument called reduce_args_. this is the header information for the struct ReduceVector.
typedef vector<string> StringVector;
// a data structure to maintain info for the reduce task
struct ReduceArg
{
ReduceArg (void); // constructor
~ReduceArg (void); // destructor
pthread_t tid; // thread id of the reduce thread
StringVector files_to_reduce; // set of files for reduce task
};
// more typedefs
typedef vector<ReduceArg *> ReduceVector;
now the issues comes when I call push_back here:
for(int i = 0; i < num_reduce_threads_ ; i++){
reduce_args_.push_back(phold);
int count = 0;
for(ShuffleSet::iterator it = shuffle_set_.begin(); it!=shuffle_set_.end(); ++it){
string line = *it;
string space = " ";
string file = line.substr(0, line.find(space)) + ".txt";
if (count < num_reduce_threads_){
cout << reduce_args_[i+1];
(reduce_args_[i+1] -> files_to_reduce)[count] = file;
//(reduce_args_[i+1] -> files_to_reduce).push_back(file);
}
count++;
//cout << ((reduce_args_.back())->files_to_reduce).back()<< endl;
}
}
both of those push_back methods cause a seg fault. the shuffle set is just a set and is outputting strings. and as noted in the .h file, the files_to_reduce is a string vector. So what I'm trying to do is access the files_to_reduce and push_back a string onto it, but each time I get a seg fault. The reduce_args_ obj is declared as below:
ReduceArg* plhold;
reduce_args_.push_back(plhold);
((reduce_args_.back()) -> files_to_reduce).push_back("hello");
for (int i = 0; i < this->num_reduce_threads_; ++i) {
// create a placeholder reduce argument and store it in our vector
(reduce_args_.push_back(plhold));
}
thanks for the help!!
This:
ReduceArg* plhold;
reduce_args_.push_back(plhold);
Unless you've hidden some important code, you're pushing an uninitialised pointer, so the next line will cause chaos.
Possibly you meant this?
ReduceArg* plhold(new ReduceArg);
..but I suspect you haven't properly thought about the object lifetimes and ownership of the object whose address you are storing in the vector.
In general, avoid pointers unless you know exactly what you're doing, and why. The code as posted doesn't need them, and I would recommend you just use something like this:
typedef vector<ReduceArg> ReduceVector;
....
reduce_args_.push_back(ReduceArg());
reduce_args_.back().files_to_reduce.push_back("hello");
for (int i = 0; i < num_reduce_threads_; ++i) {
// create a placeholder reduce argument and store it in our vector
(reduce_args_.push_back(ReduceArg());
}

Array as out parameter in c++

I created a function that returns an error code (ErrCode enum) and pass two output parameters. But when I print the result of the function, I don't get the correct values in the array.
// .. some codes here ..
ErrCode err;
short lstCnt;
short lstArr[] = {};
err = getTrimmedList(lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
// .. some codes here ..
The getTrimmedList function is like this:
ErrCode getTrimmedList(short* vList, short* vCnt)
{
short cnt;
ErrCode err = foo.getListCount(FOO_TYPE_1, &cnt);
if (NoError!=err) return err;
short* list = new short [cnt];
short total = 0;
for (short i=0; i<cnt; ++i)
{
FooBar bar = foo.getEntryByIndex(FOO_TYPE_1, i);
if (bar.isDeleted) continue;
list[total] = i;
++total;
}
*vCnt = total;
//vList = (short*)realloc(index, sizeof(short)*total);
vList = (short*)malloc(sizeof(short)*total);
memcpy(vList, list, sizeof(short)*total)
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
return NoError;
}
where:
foo is an object that holds arrays of FooBar objects
foo.getListCount() returns the number of objects with type FOO_TYPE_1
FOO_TYPE_1 is the type of object we want to take/list
foo.getEntryByIndex() returns the ith FooBar object with type FOO_TYPE_1
bar.isDeleted is a flag that tells if bar is considered as 'deleted' or not
What's my error?
Edit:
Sorry, I copied a wrong line. I commented it above and put the correct line.
Edit 2
I don't have control over the returns of foo and bar. All their function returns are ErrCode and the outputs are passed through parameter.
Couple of questions before I can answer your post...
Where is "index" defined in:
vList = (short*)realloc(index, sizeof(short)*total);
Are you leaking the memory associated with:
short* list = new short [cnt];
Is it possible you have accidentally confused your pointers in memory allocation? In any case, here is an example to go from. You have a whole host of problems, but you should be able to use this as a guide to answer this question as it was originally asked.
WORKING EXAMPLE:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int getTrimmedList(short** vList, short* vCnt);
int main ()
{
// .. some codes here ..
int err;
short lstCnt;
short *lstArr = NULL;
err = getTrimmedList(&lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d\n", i, lstArr[i]);
// .. some codes here ..
return 0;
}
int getTrimmedList(short** vList, short* vCnt)
{
short cnt = 5;
short* list = new short [cnt];
short* newList = NULL;
short total = 0;
list[0] = 0;
list[1] = 3;
list[2] = 4;
list[3] = 6;
total = 4;
*vCnt = total;
newList = (short*)realloc(*vList, sizeof(short)*total);
if ( newList ) {
memcpy(newList, list, sizeof(short)*total);
*vList = newList;
} else {
memcpy(*vList, list, sizeof(short)*total);
}
delete list;
return 0;
}
You have serious problems.
For starters, your function has only one output param as you use it: vCnt.
vList you use as just a local variable.
realloc is called with some index that we kow nothing about, not likely good. It must be something got from malloc() or realloc().
The allocated memory in vList is leaked as soon as you exit getTrimmedList.
Where you call the function you pass the local lstArr array as first argument that is not used for anything. Then print the original, unchanged array, to bounds in cnt, while it has 0 size still -- behavior is undefined.
Even if you managed to pass that array by ref, you could not reassign it to a different value -- C-style arrays can't do that.
You better use std::vector that you can actually pass by reference and fill in the called function. eliminating the redundant size and importantly the mess with memory handling.
You should use std::vector instead of raw c-style arrays, and pass-by-reference using "&" instead of "*" here. Right now, you are not properly setting your out parameter (a pointer to an array would look like "short **arr_ptr" not "short *arr_ptr", if you want to be return a new array to your caller -- this API is highly error-prone, however, as you're finding out.)
Your getTrimmedList function, therefore, should have this signature:
ErrCode getTrimmedList(std::vector<short> &lst);
Now you no longer require your "count" parameters, as well -- C++'s standard containers all have ways of querying the size of their contents.
C++11 also lets you be more specific about space requirements for ints, so if you're looking for a 16-bit "short", you probably want int16_t.
ErrCode getTrimmedList(std::vector<int16_t> &lst);
It may also be reasonable to avoid requiring your caller to create the "out" array, since we're using smarter containers here:
std::vector<int16_t> getTrimmedList(); // not a reference in the return here
In this style, we would likely manage errors using exceptions rather than return-codes, however, so other things about your interface would evolve, as well, most likely.