多线程可以加很多锁吗

发布时间:2024年01月22日

最近在做一个作业,要求用多线程处理一个很大的数据的压缩。
因为数据很大,所以将数据分成很多段,并行进行计算,我定义了一个task的数据结构来描述每个计算任务信息,比如数据大小,是否完成等等。然后再将压缩的结果合并。
问题是这样:首先每一段压缩后的结果的长度是不确定的,并且最后合并结果时也不能有空隙。这就意味着合并时必须等待每个task计算完成,但是不能等所有task计算完成再合并,因为这样合并要等很长时间,最后达不到要求。
首先我不能定义一个大的outbuf,然后让每个task将结果写入指定位置,因为每个任务不知道前面的任务的结果有多少字节,也就不知道自己的结果该写在哪。

合并在主线程中,主线程按顺序去等待task是否完成。

在这个场景中首先要考虑这几个问题:
1、每个线程task计算后的结果怎么存,是为每个task分配一个堆内存,还是提前分配一块足够大的内存。
看似2更好,因为觉得1调用太多的malloc了,但其实每个任务分配好数据后直接就去执行了,多个malloc的分配跟任务执行是并行的。

主线程在合并时需要知道线程的task是否执行完。因此我在task中添加了一个isFinish来表示当前task是否已经完成。主线程依次访问task0-n的isFinish。
如果主线程访问的task未完成,则需要等待,这里有两种办法,一种是用锁,一种是while。
用锁就面临一个问题,最开始我想用一个锁。但是不行。因为你要做的事情是计算线程进入时锁住,让主线程访问不到,等计算完成后解锁。主线程可以访问。那每个任务都有一个task要锁,所以只能每个task加锁,但是我想这样会不会造成性能问题。但是我发现这样做并不慢。
而且加锁的版本竟然比不加锁的还快。不加锁的设计是这样的,用while来等待。

 int op = 0;
  //task0
  task_data * task0 = pool->task_queue[0];
  while(task0->finish != 1){}
  memcpy(merge_buf+op , task0->result_buffer, task0->res_size);
  op+=pool->task_queue[0]->res_size;

  for(int i=1;i<pool->tasks_num;i++)
  {

    task_data * task = pool->task_queue[i];
    while(task->finish != 1){}
    ...
 }

结论

多线程编程过程中,在将大的任务分为许多小任务时,如果为每个任务加锁可以让程序逻辑更简单,那就应该这么做。也就是说,加许多的锁(万级别以下)不会造成延迟

我的误区

一开始的版本是等待所有线程计算完之后,才开始合并;我后面优化了代码,让主线程合并结果和线程的计算同步进行,并且优化版本也没加锁
一开始我不理解为何我优化的版本比不优化还要慢。
这是不优化的,也就是合并和计算不并行
在这里插入图片描述
这是优化的,合并和计算并行
在这里插入图片描述

然后我又写了一个无锁版本的合并和计算不并行的,这个是最快的
在这里插入图片描述
这说明,1、加不加锁关系不大,2、合并占用的时间极少。3、我优化的版本应该是内存存取的问题导致的耗时更长

文章来源:https://blog.csdn.net/xiaomiqaq/article/details/135699002
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。