C++并发编程实战 读书笔记--线程管理

void update_data_for_widget(int w,int& data)
{
	cout<<"hh"<<endl;
}
void oops_again(int w)
{
	int  data;
	std::thread t1(update_data_for_widget,w,std::ref(data)); 
	t1.join();
}


void f(int i,std::string const& s)
{
	cout<<"ooo"<<endl;
}
void not_oops(int some_param)
{
	char buffer[1024];
	sprintf(buffer,"%i",some_param);
	std::thread t2(f,3,buffer); 
	t2.detach();
}

在给定的代码中,t1线程的参数data是一个引用类型,而t2线程的参数buffer是一个字符数组。

在t1线程中,data是一个引用类型的参数,通过使用std::ref函数将其包装为一个std::reference_wrapper对象,然后将该对象作为参数传递给线程。这是因为线程的参数是通过值传递的,而不是通过引用传递的。通过使用std::ref,可以将引用类型的参数正确地传递给线程,以便在线程中对其进行修改。

而在t2线程中,buffer是一个字符数组,它本身就是一个指针,可以直接传递给线程作为参数。字符数组在传递给线程时,会自动转换为指向其第一个元素的指针。因此,在这种情况下,不需要使用std::ref来传递参数。

总结起来,使用std::ref来传递引用类型的参数,而对于其他类型的参数,可以直接传递给线程。这是因为引用类型的参数需要特殊处理,以确保在线程中对其进行修改时,能够正确地引用原始对象。

void some_function();
void some_other_function();
std::thread t1(some_function); // 1
std::thread t2=std::move(t1); // 2
t1=std::thread(some_other_function); // 3
std::thread t3; // 4
t3=std::move(t2); // 5
t1=std::move(t3); // 6 

移动操作 #5完成后, t1与执行some_other_function的线程相关联, t2与任何线程都无关联, t3与执行some_function的线程相关联。最后一个移动操作, 将some_function线程的所有权转移⑥给t1。 不过, t1已经有了一个关联的线程(执行some_other_function的线程), 所以这里系统直接调用 std::terminate() 终止程序继续运行。 这样做( 不抛出异常, std::terminate() 是noexcept函数)是为了保证与 std::thread 的析构函数的行为一致。 需要在线程对象被析构前, 显式的等待
线程完成, 或者分离它; 进行赋值时也需要满足这些条件(说明: 不能通过赋一个新值给 std::thread 对象的方式来"丢弃"一个线程)。

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) // 1
        return init;

    unsigned long const min_per_thread = 25;
    unsigned long const max_threads = (length + min_per_thread - 1) / min_per_thread; // 2
    unsigned long const hardware_threads = std::thread::hardware_concurrency();
    unsigned long const num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); //3
    unsigned long const block_size = length / num_threads; // 4
    
    std::vector<T> results(num_threads);
    std::vector<std::thread> threads(num_threads - 1); // 5
    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); // 6
        threads[i] = std::thread(accumulate_block<Iterator,T>(), block_start, block_end, std::ref(results[i])); // 7
        block_start = block_end; // #8
    }
    
    accumulate_block<Iterator,T>()(block_start, last, results[num_threads-1]); // 9
    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); // 10

    return std::accumulate(results.begin(), results.end(), init); // 11
}

这段代码实现了一个并行累加函数parallel_accumulate,它可以并行地对一个范围内的元素进行累加操作。

代码解释如下:

  1. 在代码的开头,定义了一个结构体accumulate_block,它重载了函数调用运算符operator()。
    这个结构体用于在每个线程中执行累加操作。
  2. parallel_accumulate函数接受两个迭代器first和last,以及一个初始值init作为参数。
    它首先计算出范围的长度length,如果长度为0,则直接返回初始值。
  3. 接下来,根据范围的长度和每个线程处理的最小元素数量min_per_thread,计算出最大线程数max_threads。
    然后,通过std::thread::hardware_concurrency()函数获取硬件支持的线程数,并将其与2进行比较,
    取较小值作为实际的线程数num_threads。
  4. 根据线程数和范围的长度,计算出每个线程处理的块大小block_size。
  5. 创建一个存储每个线程结果的向量results,以及一个存储线程对象的向量threads。
    注意,线程对象的数量比线程数少1,因为最后一个线程在主线程中执行。
  6. 使用一个循环,为每个线程创建一个块,并将其分配给对应的线程。循环中,
    首先计算块的结束迭代器block_end,然后使用std::advance函数将块的起始迭代器block_start向前移动到下一个块的起始位置。
  7. 在循环中,使用std::thread构造函数创建一个新线程,
    并将accumulate_block结构体的实例、块的起始迭代器、块的结束迭代器以及对应的结果引用作为参数传递给线程。
    注意,使用std::ref将结果引用包装起来,以便在线程中对结果进行修改。
  8. 在循环中,将块的结束迭代器赋值给下一个块的起始迭代器,以便为下一个线程创建新的块。
  9. 循环结束后,剩余的元素被分配给最后一个线程,通过调用accumulate_block结构体的实例来进行累加操作。
  10. 使用std::for_each算法和std::mem_fn函数,等待所有线程执行完毕。
  11. 最后,使用std::accumulate算法对每个线程的结果进行累加,并将初始值init与累加结果相加,得到最终的累加结果。
    总结起来,这段代码通过将范围划分为多个块,并使用多个线程并行地对这些块进行累加操作,从而提高了累加的效率。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值