Tôi cố gắng để thực hiện một container lockless thread-safe, tương tự như std :: vector, theo này https://software.intel.com/en-us/blogs/2008/07/24/tbbconcurrent_vector-secrets-of-memory-organizationThực hiện concurrent_vector theo blog của intel
Từ những gì tôi hiểu, để ngăn chặn tái phân bổ và hủy bỏ hiệu lực tất cả các vòng lặp trên tất cả các chủ đề, thay vì một mảng liền kề duy nhất, chúng thêm các khối tiếp giáp mới.
Mỗi khối họ thêm là có kích thước tăng quyền hạn là 2, vì vậy họ có thể sử dụng nhật ký (chỉ mục) để tìm phân khúc phù hợp, nơi một mục tại [index] được cho là. Từ những gì tôi thu thập, chúng có một mảng con trỏ tĩnh cho các phân đoạn, vì vậy chúng có thể truy cập chúng nhanh chóng, tuy nhiên chúng không biết số lượng phân đoạn người dùng muốn, do đó, chúng tạo ra một phân đoạn ban đầu và nếu số lượng các phân đoạn vượt quá số lượng hiện tại, chúng phân bổ một phân đoạn lớn và chuyển sang sử dụng phân đoạn đó.
Vấn đề là việc thêm phân đoạn mới không thể thực hiện được theo cách an toàn không khóa hoặc ít nhất là tôi chưa tìm ra cách. Tôi có thể tăng kích thước hiện tại một cách nguyên tử, nhưng chỉ vậy thôi.
Và cũng chuyển từ nhỏ sang mảng lớn các con trỏ phân đoạn liên quan đến một bản phân bổ lớn và bản sao bộ nhớ, vì vậy tôi không thể hiểu cách chúng đang thực hiện nó.
Họ có một số mã được đăng trực tuyến, nhưng tất cả các chức năng quan trọng là không có mã nguồn sẵn có, chúng nằm trong DLL khối xây dựng chuỗi của họ. Dưới đây là một số mã đó chứng tỏ vấn đề:
template<typename T>
class concurrent_vector
{
private:
int size = 0;
int lastSegmentIndex = 0;
union
{
T* segmentsSmall[3];
T** segmentsLarge;
};
void switch_to_large()
{
//Bunch of allocations, creates a T* segmentsLarge[32] basically and reassigns all old entries into it
}
public:
concurrent_vector()
{
//The initial array is contiguous just for the sake of cache optimization
T* initialContiguousBlock = new T[2 + 4 + 8]; //2^1 + 2^2 + 2^3
segmentsSmall[0] = initialContiguousBlock;
segmentsSmall[1] = initialContiguousBlock + 2;
segmentsSmall[2] = initialContiguousBlock + 2 + 4;
}
void push_back(T& item)
{
if(size > 2 + 4 + 8)
{
switch_to_large(); //This is the problem part, there is no possible way to make this thread-safe without a mutex lock. I don't understand how Intel does it. It includes a bunch of allocations and memory copies.
}
InterlockedIncrement(&size); //Ok, so size is atomically increased
//afterwards adds the item to the appropriate slot in the appropriate segment
}
};
Tôi không thấy bất kỳ nơi nào trong tuyên bố bài viết này chứa vùng chứa này. Tôi tin rằng bạn có thể sử dụng có mutex cho hoạt động tăng trưởng chỉ miễn là bạn giữ dữ liệu khác tại chỗ. – R2RT