代码源自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中的数据对应关系。