# Using Quiescent States to Reclaim Memory

DevFeed: [Using Quiescent States to Reclaim Memory](<https://devfeed.tech/articles/using-quiescent-states-to-reclaim-memory-21007.md>)

Original publisher: [Read original article](<https://preshing.com/20160726/using-quiescent-states-to-reclaim-memory>)

Author: Jeff Preshing

Published: 2016-07-26T10:30:00Z

Content type: article

Language: en

Sources: [Jeff Preshing](<https://devfeed.tech/sources/jeff-preshing.md>)

Topics: [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [Memory Leaks](<https://devfeed.tech/topics/memory-leaks.md>), [Scalability](<https://devfeed.tech/topics/scalability.md>), [Network](<https://devfeed.tech/topics/network.md>), [Server](<https://devfeed.tech/topics/server.md>)

Tags: [atomic](<https://devfeed.tech/tags/atomic.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [memory](<https://devfeed.tech/tags/memory.md>), [network](<https://devfeed.tech/tags/network.md>), [scalability](<https://devfeed.tech/tags/scalability.md>), [server](<https://devfeed.tech/tags/server.md>), [structure](<https://devfeed.tech/tags/structure.md>), [thread](<https://devfeed.tech/tags/thread.md>), [vector](<https://devfeed.tech/tags/vector.md>)

## AI overview

This article explains how to reclaim memory safely in a multithreaded C++ program by replacing a read-write-locked data structure with immutable copies referenced through an atomic pointer. It introduces quiescent states to determine when older copies are no longer in use and can be deleted, preserving scalability while avoiding memory leaks.

## Source excerpt

If you want to support multiple readers for a data structure, while protecting against concurrent writes, a read-write lock might seem like the only way - but it isn't! You can achieve the same thing without a read-write lock if you allow several copies of the data structure to exist in memory. You just need a way to delete old copies when they're no longer in use. Let's look at one way to achieve that in C++. We'll start with an example based on a read-write lock. Using a Read-Write Lock Suppose you have a network server with dozens of threads. Each thread broadcasts messages to dozens of connected clients. Once in a while, a new client connects or an existing client disconnects, so the list of connected clients must change. We can store the list of connected clients in a std::vector and protect it using a read-write lock such as std::shared_mutex. class Server { private: std::shared_mutex m_rwLock; // Read-write lock std::vector<int> m_clients; // List of connected clients public: void broadcast(const void* msg, size_t len) { std::shared_lock<std::shared_mutex> shared(m_rwLock); // Shared lock for (int fd : m_clients) send(fd, msg, len, 0); } void addClient(int fd) { std::unique_lock<std::shared_mutex> exclusive(m_rwLock); // Exclusive lock m_clients.push_back(fd); } ... The broadcast function reads from the list of connected clients, but doesn't modify it, so it takes a read lock (also known as a shared lock). addClient, on the other hand, needs to modify the list, so it takes a write lock (also known as an exclusive lock). That's all fine and dandy. Now let's eliminate the read-write lock by allowing multiple copies of the list to exist at the same time. Eliminating the Read-Write Lock First, we must establish an atomic pointer to the current list. This pointer will hold the most up-to-date list of connected clients at any moment in time. class Server { private: struct ClientList { std::vector<int> clients; }; std::atomic<ClientList*> m_currentList; // The most