Is std::vector or boost::vector Thread Safe?
Last Updated :
01 Aug, 2024
In C++, a common question that arises is: Is std::vector or boost::vector thread-safe? The straightforward answer is no, neither std::vector nor boost::vector is thread-safe.
In this article, we will learn why std::vector and boost::vector are not thread-safe and explore some practical alternatives for making them safe to use in a multi-threaded environment.
What is Thread Safety?
Thread safety refers to the property of a program or code segment that ensures correct behavior when accessed from multiple threads simultaneously. A thread-safe component can be used by multiple threads concurrently without causing data races or inconsistent states.
Problems with Thread Safety in std::vector and boost::vector
std::vector is a part of the C++ Standard Library, widely used for dynamic array implementations whereas boost::vector is part of the Boost Libraries, designed to extend the functionalities of the C++ Standard Library. However, both std::vector and boost::vector are not inherently thread-safe.
1. Concurrent Read-Write Access
Simultaneous read and write operations on the same std::vector or boost::vector instance can cause undefined behavior due to data races.
2. Concurrent Write Access
Simultaneous write operations (e.g., modifying, inserting, or deleting elements) are not safe without external synchronization mechanisms.
3. Lack of Built-in Synchronization
Neither std::vector nor boost::vector provides built-in mechanisms to handle concurrent access, which means the user must handle synchronization.
How to Ensure Thread Safety with std::vector and boost::vector
To make std::vector or boost::vector thread-safe, we need to use synchronization mechanisms like mutexes.
For std::vector
We can use a std::mutex to ensure mutual exclusion, which prevents multiple threads from accessing the vector simultaneously. Using this we can protect read and write operations to ensure mutual exclusion.
Example:
C++
// C++ program to demonstrate thread-safe read and write
// operations on a vector using mutexes
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
// Use the standard namespace
using namespace std;
// Global vector to store integers
vector<int> vec;
// Mutex to protect vector access
mutex vecMutex;
// Function to read elements from the vector
void readVector()
{
// Lock the mutex to ensure exclusive access
lock_guard<mutex> guard(vecMutex);
// Print the elements in the vector
cout << "Reading from vector: ";
for (const auto& elem : vec) {
cout << elem << " ";
}
cout << endl;
}
// Function to write elements to the vector
void writeVector()
{
// Lock the mutex to ensure exclusive access
lock_guard<mutex> guard(vecMutex);
// Add elements to the vector
for (int i = 0; i < 10; ++i) {
vec.push_back(i);
}
// Indicate that writing to the vector is complete
cout << "Writing to vector completed." << endl;
}
int main()
{
// Create a thread to read from the vector
thread t1(readVector);
// Create a thread to write to the vector
thread t2(writeVector);
// Create another thread to read from the vector
thread t3(readVector);
// Wait for the first thread to finish
t1.join();
// Wait for the second thread to finish
t2.join();
// Wait for the third thread to finish
t3.join();
return 0;
}
Output
Reading from vector:
Writing to vector completed.
Reading from vector: 0 1 2 3 4 5 6 7 8 9
For boost::vector
Using boost::vector in a thread-safe manner requires similar synchronization techniques as std::vector, so we can use boost::mutex to ensure thread safety when using boost::vector.
Example:
C++
// C++ program to demonstrate thread safe concurrent
// read/write access to a vector using Boost libraries for
// thread synchronization
// Include necessary Boost headers
#include <boost/container/vector.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
// Include standard I/O stream header
#include <iostream>
// Use the standard namespace
using namespace std;
// Define a vector using Boost's container library
boost::container::vector<int> vec;
// Define a mutex using Boost's thread library
boost::mutex vecMutex;
// Function to read and print elements from the vector
void readVector()
{
// Lock the mutex to ensure thread-safe access
boost::lock_guard<boost::mutex> guard(vecMutex);
// Print a message indicating the read operation
cout << "Reading from vector: ";
// Iterate over elements in the vector and print them
for (const auto& elem : vec) {
cout << elem << " ";
}
// Print a new line at the end
cout << endl;
}
// Function to write elements to the vector
void writeVector()
{
// Lock the mutex to ensure thread-safe access
boost::lock_guard<boost::mutex> guard(vecMutex);
// Write numbers 0 to 9 to the vector
for (int i = 0; i < 10; ++i) {
vec.push_back(i);
}
// Print a message indicating the write operation is
// complete
cout << "Writing to vector completed." << endl;
}
// Main function
int main()
{
// Create three threads to read and write to the vector
boost::thread t1(readVector);
boost::thread t2(writeVector);
boost::thread t3(readVector);
// Wait for all threads to finish execution
t1.join();
t2.join();
t3.join();
// Return 0 to indicate successful execution
return 0;
}
Output
Reading from vector:
Writing to vector completed.
Reading from vector: 0 1 2 3 4 5 6 7 8 9
Conclusion
Neither std::vector nor boost::vector is inherently thread-safe. To safely use these containers in a multi-threaded environment, we must use external synchronization mechanisms such as std::mutex or boost::mutex to ensure thread safety and to prevent data races for maintaining consistent states when accessing shared data structures concurrently.
Similar Reads
std::vector::resize() vs. std::vector::reserve()
In C++, vector resize() and vector reserve() are two member methods of vector to manage memory of the container. In this article, we will learn the differences between vector resize() and vector reserve() method in C++. Vector size() modifies the size of the vector, i.e., the number of elements curr
3 min read
vector::at() and vector::swap() in C++ STL
In C++, vector at() is a built-in method used to access an element in a vector using index. It is the only access method that performs bound checking before accessing the element to confirm whether the given index lies is within the vector. Letâs take a quick look at a simple example that uses vecto
3 min read
vector::empty() and vector::size() in C++ STL
In C++, vector empty() is a built-in method used to check whether the given vector is empty or not. In this article, we will learn about vector empty() method in C++. Letâs take a look at an example that illustrates the vector empty() method: [GFGTABS] C++ #include <bits/stdc++.h> using namesp
2 min read
What is thread safe or non-thread safe in PHP ?
Thread-safe: It is used to ensure that when the shared data structure which is manipulated by different threads are prevented from entering the race condition. Thread-safety is recommended when the web server run multiple threads of execution simultaneously for different requests. In Thread Safety b
2 min read
vector::begin() and vector::end() in C++ STL
In C++, the vector end() is a built-in method used to obtain an iterator pointing to the theoretical element after the last element of the vector. Even though this iterator does not point to a valid element, it serves as a marker for the end of the vector. Letâs take a look at an example that illust
4 min read
Vector of Vectors in C++ STL with Examples
Prerequisite: Vectors in C++ STL Vectors are known as dynamic arrays with the ability to resize itself automatically when an element is inserted or deleted, with their storage being handled automatically by the container. Vector of Vectors is a two-dimensional vector with a variable number of rows w
5 min read
Difference between std::remove and vector::erase for vectors
std::remove : It doesn't actually delete elements from the container but only shunts non-deleted elements forwards on top of deleted elements. vector::erase : Removes from the vector either a single element (position) or a range of elements ([first, last)). std::remove vs vector::erase By using eras
4 min read
vector::push_back() and vector::pop_back() in C++ STL
In C++, the vector push_back() is a built-in method used to add a new element at the end of the vector. It automatically resizes the vector if there is not enough space to accommodate the new element. Letâs take a look at an example that illustrates the vector push_back() method: [GFGTABS] C++ #incl
2 min read
vector::operator= and vector::operator[ ] in C++ STL
In C++, the vector operator [] is used to randomly access or update the elements of vector using their indexes. It is similar to the vector at() function but it doesn't check whether the given index lies in the vector or not. Letâs take a look at a simple code example: [GFGTABS] C++ #include <bit
3 min read
vector::front() and vector::back() in C++ STL
In C++, the vector front() is a built-in function used to retrieve the first element of the vector. It provides a reference to the first element, allowing you to read or modify it directly. Letâs take a quick look at a simple example that uses the vector front() method: [GFGTABS] C++ #include <bi
2 min read