线程归属权
线程归属权是基于C++的thread库来讲的,线程库要求创建一个thread类型的变量来表示一个线程,那么该线程的所属权就是该thread变量
线程所属权的改变
- 使用
std::move
来移动线程变量,将其转移给其他线程变量 - 该线程使用
detach
方法,让线程在后台运行,此时线程的所属权转交给后台
线程所属权的注意点
不要对已经绑定的线程进行另一个线程所属权的赠与,也就是一个线程只能执行一个任务,不能同时管理两个线程,否则会触发terminate
是因为当一个正在执行的线程被赠与另一个线程的所有权,那么就会造成原线程的终止,从而出发析构函数的terminate
void some_function() {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void some_other_function() {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
std::thread t1(some_function);
std::thread t2 = std::move(t1);
t1 = std::thread(some_other_function);
std::thread t3;
t3 = std::move(t2);
std::this_thread::sleep_for(std::chrono::seconds(2000));
return 0;
}
joining_thread的封装
该封装的目的是在析构函数中自动汇合
class joining_thread{
std::thread _t;
public:
joining_thread() = default;
template<typename Callable , typename ...Args>
explicit joining_thread(Callable&& Fn , Args&& ... args)
:_t(std::forward<Callable>(Fn),std::forward<Args>(args)...)
{}
explicit joining_thread(std::thread t) noexcept: _t(std::move(t)){}
joining_thread(joining_thread&& other) noexcept:_t(std::move(other._t)){}
joining_thread& operator=(joining_thread&& other) noexcept
{
//如果当前线程可汇合,则汇合等待线程完成再赋值
if (joinable()) {
join();
}
_t = std::move(other._t);
return *this;
}
joining_thread& operator=(joining_thread other) noexcept
{
//如果当前线程可汇合,则汇合等待线程完成再赋值
if (joinable()) {
join();
}
_t = std::move(other._t);
return *this;
}
~joining_thread() noexcept {
if (joinable()) {
join();
}
}
void swap(joining_thread& other) noexcept {
_t.swap(other._t);
}
std::thread::id get_id() const noexcept {
return _t.get_id();
}
bool joinable() const noexcept {
return _t.joinable();
}
void join(){
_t.join();
}
void detach(){
_t.detach();
}
std::thread& as_thread() noexcept {
return _t;
}
const std::thread& as_thread() const noexcept {
return _t;
}
};
容器存储
下面是使用容器的两种等价的写法
void use_vector(){
std::vector<std::thread> threads;
for(int i = 0 ; i < 2 ; i ++)
{
std::thread t(thread_worker);
threads.push_back(std::move(t));
threads.emplace_back(thread_worker);
}
}
std::move的一个知识点
在一个类没有实现移动构造函数但是实现了拷贝构造函数时,构造该类对象传入std::move(对象)会调用类的拷贝构造
多线程的应用:并行计算
template<typename Iterator, typename T>
struct accumulate_block{
void operator()(Iterator first , Iterator last , T& result){
result = std::accumulate(first,last,result);
}
};
template<typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
unsigned long const length = std::distance(first, last);
if (!length)
return init; //⇽-- - ①
unsigned long const min_per_thread = 25;
unsigned long const max_threads =
(length + min_per_thread - 1) / min_per_thread; //⇽-- - ②
unsigned long const hardware_threads =
std::thread::hardware_concurrency();
unsigned long const num_threads =
std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); //⇽-- - ③
unsigned long const block_size = length / num_threads; //⇽-- - ④
std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_threads - 1); // ⇽-- - ⑤
Iterator block_start = first;
for (unsigned long i = 0; i < (num_threads - 1); ++i)
{
Iterator block_end = block_start;
std::advance(block_end, block_size); //⇽-- - ⑥
threads[i] = std::thread(//⇽-- - ⑦
accumulate_block<Iterator, T>(),
block_start, block_end, std::ref(results[i]));
block_start = block_end; //⇽-- - ⑧
}
accumulate_block<Iterator, T>()(
block_start, last, results[num_threads - 1]); //⇽-- - ⑨
for (auto& entry : threads)
entry.join(); //⇽-- - ⑩
return std::accumulate(results.begin(), results.end(), init); //⇽-- - ⑪
}
void use_parallel_acc() {
std::vector <int> vec(10000);
for (int i = 0; i < 10000; i++) {
vec.push_back(i);
}
int sum = 0;
sum = parallel_accumulate<std::vector<int>::iterator, int>(vec.begin(),
vec.end(), sum);
std::cout << "sum is " << sum << std::endl;
}