代碼源自C++ Concurrency in Action Second Edition
#include <list>
template<typename T>
struct sorter
{
struct chunk_to_sort
{
std::list<T> data;
std::promise<std::list<T> > promise;
};
thread_safe_stack<chunk_to_sort> chunks;
std::vector<std::thread> threads;
unsigned const max_thread_count;
std::atomic<bool> end_of_data;
sorter() :
max_thread_count(std::thread::hardware_concurrency() - 1),
end_of_data(false)
{}
~sorter()
{
end_of_data = true;
for (unsigned i = 0; i < threads.size(); ++i)
{
threads[i].join();
}
}
void try_sort_chunk()
{
std::shared_ptr<chunk_to_sort > chunk = chunks.pop();
if (chunk)
{
sort_chunk(chunk);
}
}
std::list<T> do_sort(std::list<T>& chunk_data)
{
if (chunk_data.empty())
{
return chunk_data;
}
std::list<T> result;
// 將chunk_data中第一個元素取出放入result
result.splice(result.begin(), chunk_data, chunk_data.begin());
// 將該元素值作爲base值
T const& partition_val = *result.begin();
// 將chunk_data中剩餘元素根據base值分區
typename std::list<T>::iterator divide_point =
std::partition(chunk_data.begin(), chunk_data.end(),
[&](T const& val) {return val < partition_val; });
// 小於base值的部分保存至new_lower_chunk,splice之後的chunk_data即爲大於base值的部分
chunk_to_sort new_lower_chunk;
new_lower_chunk.data.splice(new_lower_chunk.data.end(),
chunk_data, chunk_data.begin(),
divide_point);
// 小於base部分的list壓入全局類型棧
std::future<std::list<T> > new_lower =
new_lower_chunk.promise.get_future();
chunks.push(std::move(new_lower_chunk));
// 線程數組添加線程 ??如果超過最大線程數會怎樣??
if (threads.size() < max_thread_count)
{
threads.push_back(std::thread(&sorter<T>::sort_thread, this));
}
// 大於base值的部分遞歸調用自身,繼續進行分區排序
std::list<T> new_higher(do_sort(chunk_data));
// 將排好序的大於base部分的list拼接到result
result.splice(result.end(), new_higher);
// 小於base部分的list如果未完成則調用try_sort_chunk
while (new_lower.wait_for(std::chrono::seconds(0)) !=
std::future_status::ready)
{
try_sort_chunk();
}
// 將排好序的小於base部分list拼接到result,形成完整排好序的list
result.splice(result.begin(), new_lower.get());
// 返回結果
return result;
}
void sort_chunk(std::shared_ptr<chunk_to_sort > const& chunk)
{
chunk->promise.set_value(do_sort(chunk->data));
}
void sort_thread()
{
while (!end_of_data)
{
try_sort_chunk();
std::this_thread::yield();
}
}
};
template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input)
{
if (input.empty())
{
return input;
}
sorter<T> s;
return s.do_sort(input);
}
do_sort函數中每次將list切割爲大小兩部分後,大的部分遞歸調用do_sort,小的部分起一個線程,並將list入棧,每個線程pop一個list來進行處理 ,棧的下一層用future等待上一層完成,每個線程都一直嘗試pop stack中的list進行sort,直至全部排序完成。
這裏只是儘可能多的起線程去處理stack中的list,不是和stack中的數據對應關係。