mercredi 25 mars 2015

Deleting data in atomic / fenced data

Assume we use the standard consumer/producer pattern in our C++11 program: (from: http://ift.tt/1krieqi)



#include <thread>
#include <atomic>
#include <cassert>
#include <string>

std::atomic<std::string*> ptr;
int data;

void producer()
{
std::string* p = new std::string("Hello");
ptr.store(p, std::memory_order_release);
}

void consumer()
{
std::string* p2;
while (!(p2 = ptr.load(std::memory_order_consume)))
;
assert(*p2 == "Hello"); // never fires: *p2 carries dependency from ptr

// yea well, it actually uses p2 for quite a while probably....
}

int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join(); t2.join();
}


Now, I would like to change the behavior of the producer code just a bit. Instead of simply setting a string, I'd like it to overwrite a string. E.g.:



void producer()
{
std::string* p = new std::string("Hello");
ptr.store(p, std::memory_order_release);

// do some stuff

std::string* p2 = new std::string("Sorry, should have been Hello World");
ptr.store(p2, std::memory_order_release);

// **
}


The producer here is responsible for the generation of the strings, which means that in my simple world it should also be responsible for the destruction of these strings.


In the line marked with '**' we should therefore destroy string 'p', which is what this question is about.


The solution you might consider would be to add (at the marked line):



delete p;


However, this will break the program, since the consumer might be using the string after we've deleted it -- after all, the consumer uses a pointer. Also, this implies that the producer waits for the consumer, which isn't necessary - we just want our old memory to be cleaned up. Using a ref counting smart pointer seems to be out of the question, since atomic only supports that many types.


What's the best (most efficient) way to fix this?


Aucun commentaire:

Enregistrer un commentaire