void try_reclaim(node* old_head) { if (threads_in_pop == 1) { // claim list of to-be-deleted nodes node* nodes_to_delete = to_be_deleted.exchange(nullptr); // are you the only thread in pop()? if (!--threads_in_pop) { // on other thread can be accessing this list of pending nodes. // There may be new pending nodes, but you're not bothered // about them for now, as long as it's safe to reclaim your // list. delete_nodes(nodes_to_delete); } else if (nodes_to_delete) { // not safe to reclaim the nodes, so if there are any, // you must chain them back onto the list of nodes // pending deletion. // This can happen if there are multiple threads accessing the // data structure concurrently. Other threads might have // called pop() in between the first tet of thread_in_pop and // the "claiming" of the list, potentially adding new nodes to // the list that are still being accesed by one or more of // those other threads. chain_pending_nodes(nodes_to_delete); } delete old_head; } else { // not safe to delete any nodes, add the node to the pending list chain_pending_node(old_head); --threads_in_pop; } }
void lock_free_stack<T>::try_reclaim(Node* old_head) { if (threads_in_pop == 1) //единственный в pop() => попытка удалить { //можно безопасно удалять только что исключенный из списка old_head delete old_head; //Пытаемся удалить накопившиеся исключенные узлы Node* nodes_to_delete = to_be_deleted.exchange(nullptr); //захватить список на удаление if (!--threads_in_pop)//точно единственный? { //удаляем узлы, накопившиеся в списке nodes_to_delete while(nodes_to_delete) { Node* next = nodes_to_delete->next; delete nodes_to_delete; nodes_to_delete = next; } } else if(nodes_to_delete) { chain_pending_nodes(nodes_to_delete); } //если в захваченном списке что-то было, вернуть это в общий список узлов на удаление } else { //удалять old_head сейчас нельзя => добавим в список для удаления (удалим как-нибудь потом) chain_pending_node(old_head); --threads_in_pop; } }
void try_reclaim(node* old_head) { if (1 == threads_in_pop) { node* nodes_to_delete = to_be_deleted.exchange(nullptr); if (!--threads_in_pop) { delete_nodes(nodes_to_delete); } else if(nodes_to_delete) { chain_pending_nodes(nodes_to_delete); } delete old_head; } else { chain_pending_node(old_head); --threads_in_pop; } }