I need to make small code refactoring i queueing/dequeueing operation in multi-thread application. Current implementation is:
enqueueing function is called with argument:
enqueue(obj_ptr item)
where obj_ptr is pointer to class obj created using shared_ptr. Then, given items (type obj_ptr) are enqueued in std list
list<obj_ptr>
and simply dequeued using front() and pop_front() and sent further. Everything works fine in this implementation.
What i want to do is:
Enqueue this items in special list using its API:
a_enqueue(void *buffer)
So I need the direct address to buffer.
I was thinking about use:
item->get()
which returns type obj but then I could only dequeue obj, not obj_ptr which is expected to next operations after dequeueing (+ I would loose information about class references and it will destroy multi-thread app)
I was thinking about provide to list pointer to obj_ref item:
a_enqueue(&item)
But item is created in some function long time ago and put as argument many times (not as pointer) and it is not possible to find direct address to it.
The best way for me is to enqueue buffer obj (item->get()), then dequeue and find somehow the same reference obj_ptr item I used in get(). Is it possible? Any other ideas?
Thanks.
Edit: Dequeue call is:
a_dequeue(void **buffer)
What does the API dequeue look like?
Usually if you're enqueueing void *, you're also defining a handler function so you can do something like this...
void enqueue_ptr (obj_ptr enqueue_me)
{
// Making a copy on the heap increments the ptr count
obj_ptr * heap_ptr = new obj_ptr(enqueue_me);
a_enqueue (heap_ptr);
}
obj_ptr dequeue_ptr (void)
{
// You might need casting to change void * to obj_ptr *
obj_ptr * heap_ptr;
a_dequeue (&heap_ptr);
// Sticking the copy in an auto_ptr decrements the ptr count when we leave scope.
std::auto_ptr<obj_ptr> obj_pptr(heap_ptr);
return *obj_pptr;
}
Basically, you treat the obj_ptr the same as you would any other object being passed around as a void *.
Related
I get a data structure like this:
struct My_data
{
MyArray<float> points;
MyArray<float> normals;
MyArray<float> uvCoords;
};
This function can be used to free them:
void ClearAlembicData(My_data* myData)
{
myData->points.clear();
myData->normals.clear();
myData->uvCoords.clear();
}
I want to asynchronously clean the myData so that the program will not wait util all the xxx.clear() are done. Here is my actual code:
My_data myData;
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
ClearAlembicData(&myData);
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
Could you show me how to do it in C++? thanks
Depending on the definition of MyArray, this will either cause undefined behavior or be completely pointless.
If the container is thread-safe, it will block your push_back while the clear is being executed in the other thread (making the 'clearing it asynchronously' completely pointless), if it is not, you are introducing a race condition, which might even end up crashing your program, because you would be concurrently manipulating a shared resource. (Not a good idea).
If you still want to do it, here is a way that might work:
Make 'myData' into a pointer and operate on that.
Upon wanting to clear, store that pointer in another pointer variable and replace the pointer with new My_Data.
Pass the stored pointer to your asynchronous 'free' function.
Continue to work with your new data structure in the original thread.
This way, you are not working on a shared resource and asynchronous freeing becomes feasible.
As for 'how to', if you've got C++11, something like this would work (Pseudo-Code).
My_data *myData = new My_data();
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
std::thread([=](){ ClearAlembicData(myData); delete myData; }).detach();
myData = new My_data()
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
delete myData;
One of the solutions, implement MyArray::swap(MyArray&). Then
void ClearAlembicData(My_data* myData)
{
MyArray<float> old_points;
MyArray<float> old_normal;
MyArray<float> old_coords;
// Fast swap, myData arrays become empty
myData->points.swap(old_points);
myData->normals.clear(old_normals);
myData->uvCoords.clear(old_coords);
// Assumed to be passed to async function
old_points.clear();
old_normals.clear();
old_coords.clear();
}
There is no enough information about MyArray abilities, such as support of move semantics, a real function clear, thus this is just an idea.
If MyArray is a wrapper around std::vector, know that the clear() operation is O(1) as float is trivially destructible and the compiler can eliminate the loop that destroys elements individually.
If it is not, consider implementing MyArray.clear() such that it marks the container as having a non-zero capacity yet zero contents. As stated above, std::vector accomplishes this by simply setting slots_available = capacity.
I have a QList and I'm trying to replace the objects in the list with new objects. The context is that I have a list of custom objects (the class name is "Conversation") to represent a list of group chats in a messaging platform. I use std::find_if to iterate through the list of pointers to find one with the right ID, and I want to take the pointer to that found object, deallocate it (delete?), and reassign that pointer to point at an object I generate with the "new" keyword. I think I'm doing this right but I'm not sure how to verify.
I tried a couple different iterations, ran into some issues where I realized I was using a const_iterator rather than just an iterator, so I couldn't modify any data. But I've fixed that and it seems like it's working, but I'm not positive.
Here's what I've got:
GroupChat *gc = new GroupChat(); // extends Conversation
// ...I update the member data here...
auto foundChat = std::find_if(conversations_.Conversations.begin2(),
conversations_.Conversations.end2(),
[this, gc](Conversation* o) { // my code to find the correct one...
}
if (foundChat != conversations_.Conversations.end()) {
auto c = (*foundChat);
delete c; // Is this right? Not positive...
//*foundChat = nullptr; // do I need this?
c = gc;
}
It seems like it's working but I'm worried about dangling pointers and incorrect memory deallocation/allocation. Could someone spot check me on this? Thanks for any help!
I'm working on using pointers to add objects to a queue and ran into a weird behavioral problem I can't quite figure out.
Each object that gets added to the queue has a 'next' pointer that links them all together and I have a 'start' and 'end' pointer to keep track where each end of the queue is.
The problem I have is that when I pass the end pointer and the object (which is stored in pArray by its processID), it also changes the start pointer -- even though I'm not passing it to the function.
// snippet from my main.cpp
RQCount = 0;
if (RQCount == 0)
{
RQStart = &pArray[processID];
RQStart -> next = &pArray[processID];
endRQ = &pArray[processID];
pArray[processID].setStatus("Ready");
CPUHolder = RQStart;
CPU = RQStart -> CPUBurst;
RQStart ->pStatus = "Executing";
}
else
{
*endRQ = FCFS(endRQ, &pArray[processID]);
pArray[processID].setStatus("Ready")
}
RQCount++;
FCSC Method:
PCB FCFS (PCB *endRQ, PCB *obj)
{
endRQ -> next = obj;
endRQ = obj;
return *endRQ;
};
I've narrowed it down to the function, and what really stumps me is that I move those two lines of code to my main, it runs and behaves just fine. It's when I add the function it doesn't. I think it has to do with how I'm dealing with the pointers and dereferencing, but I could use some help understanding this. Thanks!
EDIT:
To emphasize, I'm not having an issue with variables not changing in the function, as someone marked this a duplicate question for. The issue is after the function is called, it changes RQStart (which is not passed to the function).
If I don't use a function, RQStart stay the same, when I use the function, RQStart changes to a different object.
If you do
RQStart = &pArray[processID];
// ...
endRQ = &pArray[processID];
and then pass endRQ to the function, that will be the same as if you passed RQStart.
So when you change endRQ->next that will also change RQStart->next.
This is one reason for the standard containers to have end() point one past the last element, and not to the last element.
So I am building a simulator in order to simulate some load balancing algorithms. I have created 2 vectors of Cores and Dispatchers as shown below:
std::vector<std::unique_ptr<Dispatcher> > vDisp;
std::vector<std::unique_ptr<Core> > vCore;
The class dispatcher has a queue for the cores in order to assign to them the jobs.
std::queue<Core> disp_core_queue;
Plus I have some functions in order to handle this queue:
void add_core_q(Core& p){ disp_core_queue.push(p); }
Core get_core_q(){ return disp_core_queue.front(); }
When the program initializes I populate the cores and disps like this:
for (auto i=0; i<dispNumb; ++i)
{
vDisp.push_back(std::unique_ptr<Dispatcher> (new Dispatcher));
std::cout<<"Disp n."<<i<<" Created"<<std::endl;
}
My problem is that I cannot get a Core from the vector and store it inside a Dispatcher's queue. I have tried many ways but it seems C++ punishes me for various reasons. My last try was this one from inside the Dispatcher:
int kore = random_core();
this->add_core_q(vCore.at(kore));
Which gave this error in compile time:
error: no matching function for call to 'Dispatcher::add_core_q(_gnu_cxx::__alloc_traits > >::value_type&) '
candidate is:
void Dispatcher::add_core_q(Core&)
no known conversion for argument 1 from '__gnu_cxx::__alloc_traits > >::value_type {aka std::unique_ptr}' to 'Core&'
If anyone could give me a hint I would greatly appreciate it. Thanks in advance.
The function signature for add_core_q is taking Core&.
You are passing in a std::unique_ptr.
Your Core objects are stored inside unique_ptr's yet your add_core_q method requires a Core reference.
You could get the raw pointer from the unique_ptr and dereference it which would allow you to do this:
add_core_q(*(vCore[0]));
However you're also going to have a problem with your get_core_q method since it returns a copy of the Core object rather than a reference to the Core stored in the unique_ptr.
Personally I'd just pass around pointers rather than dereferencing things. So you'd change your add_core_q method to accept a raw pointer:
void add_core_q(Core* p){ disp_core_queue.push(p); }
Which you would use like this:
add_core_q(vCore[0].get());
You'd also have to change your queue to store pointers rather than the objects themselves:
std::queue<Core*> disp_core_queue;
And you'll need to change the return type of your get method to a pointer.
Core* get_core_q(){ return disp_core_queue.front(); }
Though if you're more comfortable with references you could return a reference instead:
Core& get_core_q(){ return *(disp_core_queue.front()); }
(Disclaimer: I have removed the Qt tag in case the problem is in my syntax / understanding of the references involved here)
I have a foreach loop with an object Member. When I enumerate through the list and try to access a member field, the debugger stops and I get a message:
Stopped: 'signal-received' -
The assert failure is:
inline QString::QString(const QString &other) : d(other.d)
{ Q_ASSERT(&other != this); d->ref.ref(); }
I have checked if the member is NULL, and it isn't. I have tried re-working the code, but I keep failing on this simple call.
Some thing's I missed out. MemberList is a singleton (definitely initialized and returns a valid pointer) that is created as the application launches and populates the MemberList with Members from a file. When this is created, there are definitely values, as I print them to qDebug(). This page is literally the next page. I am unsure as to how the List items can be destroyed.
The code is as follows:
int i = 0;
QList<Member*> members = ml->getMembers();
foreach (Member* mem, members)
{
QString memID = mem->getMemberID(); // Crash happens here
QListWidgetItem *lstItem = new QListWidgetItem(memID, lsvMembers);
lsvMembers->insertItem(i, lstItem);
i++;
}
The Member classes get is as follows:
QString getMemberID() const;
and the actual function is:
QString Member::getMemberID() const
{
return MemberID;
}
The ml variable is received as follows:
QList<Member*> MemberList::getMembers()
{
return MemberList::getInstance()->memberList;
}
Where memberList is a private variable.
Final answer:
I decided to rework the singleton completely and found that I was not instantiating a new Member, rather reusing the previous object over and over. This caused the double reference. S'pose thats pointers for you. Special thanks to Troubadour for the effort!
If mem is not null it could still be the case that the pointer is dangling i.e. the Member it was pointing to has been deleted.
If Member inherits from QObject then you could temporarily change your QList<Member*> that is stored in ml (assuming that's what's stored in ml) into a QList< QPointer<Member> >. If you then get a null QPointer in the list after calling getMembers or at any point during the loop then the object must have been destroyed at some point.
Edit
As regards the singleton, are you sure it's initiliased properly? In other words does MemberList::getInstance() return a valid pointer or just a random uninitialised one?
Edit2
Since we've exhausted most possibilities I guess it must be in the singleton somewhere. All I can suggest is to keep querying the first item in the list to find out exactly where it goes bad.