酚醛保温板制作工艺|苏洋建材

四川建材 2021-10-22 阅读:180

酚醛保温板制作工艺

  看了几篇别人写得文章,感觉写得模模糊糊的。。于是自己去读了读。

  本文不仅精确而且完备。看了本文之后,即使自己实现一套智能指针也没有问题。

  下文中

  “智能指针”指shared_ptr或weak_ptr

  “裸指针”指原始的C指针

  裸指针还是智能指针通常是上下文自明的,此时直接用“指针”一词指代两者之一

  首先,我们来看shared_ptr和weak_ptr持有了哪些数据。

  对于shared_ptr和weak_ptr,都仅持有两个字段,指向对象地址的指针ptr,和指向计数器对象的指针rep。

  对于计数器对象,我们仅需要关心两个字段,一个是弱引用计数weaks(无符号整型),一个是强引用计数uses(无符号整型)。

  那么,若s1,s2是仅有的两个指向对象obj的shared_ptr,w1,w2,w3是仅有的三个指向对象obj的weak_ptr,则以上所有的智能指针(s1,s2,w1,w2,w3)的ptr字段保存着obj的地址,所有的rep字段指向同一个计数器对象(记为c1),c1的weaks字段现在是4(3+1,为什么加一后面会讲),uses字段现在是2。

  此时,为了我写着方便,我们可以将s1和c1简记为 s1=(&obj,&c1);c1=(u:2,w:4)

  指针中两个字段:ptr,rep。计数对象中两个字段:uses,weaks。请捋顺之后再向下阅读。

  下面,我们来结合例子来讲每个操作背后发生了什么,注意:例子是连续的,即上一个操作的结束是下一个操作的开始。

  操作1:构造新的空指针

  shared_ptr s1,s2;

  weak_ptr w1;

  初始化操作十分简单,s1,s2和w1的ptr和rep都被初始为了NULL,

  记作s1=s2=w1=(NULL,NULL)

  操作2:使用裸指针构造智能指针

  int* a=new int(1);

  int* b=new int(2);

  s1.reset(a);

  发生条件:用裸指针reset智能指针,或将裸指针作为参数调用构造函数

  执行过程:

  //创建一个新的计数器对象(记为c1),计数器对象的weaks和uses都初始为1

  new c1=(u:1,w:1);

  // 将s1的ptr赋值为裸指针a,将s1的rep指向c1

  s1=(a,&c1);

  操作3:从强引用构造智能指针

  s2=s1; // uses计数+1

  w1=s1; // weaks计数+1

  weak_ptr w2(w1); // weaks计数+1

  发生条件:用shared_ptr构造智能指针或赋值空的智能指针。用weak_ptr构造weak_ptr或赋值空的weak_ptr。

  执行过程:

  // 若右值的rep非空,则复制右值的rep到左值,然后将rep的uses或weaks计数原子+1

  if(s1.rep&&s1.rep->uses或weaks计数原子+1)

  s2.rep=s1.rep;

  s2.ptr=s1.ptr;

  结果:

  c1=(u:2,w:3);s1=s2=w1=w2=(a,&c1)

  以下结论始终成立:

  uses计数=实际强引用数。

  weaks计数=

  1.实际弱引用数+1(当uses计数不为0)

  2.实际弱引用数(当uses计数为0)

  如果uses计数不为0,则weaks计数至少为1

  操作4:从弱引用构造强引用

  shared_ptr s3(w1)

  发生条件:用weak_ptr,构造或赋值空的shared_ptr。执行weak_ptr的lock函数

  执行过程:

  if(w1.rep){

  将w1.rep->uses字段加乐观锁{

  if(w1.rep->uses!=0){

  w1.rep->uses++;

  s3.rep=w1.rep;

  s3.ptr=w1.ptr;

  }else{

  抛出bad_weak_ptr异常

  }

  }

  }

  结果:

  c1=(u:3,w:3);s1=s2=s3=w1=w2=(a,&c1)

  操作5:释放弱引用

  w1.reset

  发生条件:1.对weak_ptr做reset。2.见“一些组合操作”

  执行过程:

  w1.ptr=NULL;

  w1.rep=NULL;

  if(w1.rep->原子操作weaks-1并返回新的值==0){

  释放对象 w1.rep;

  }

  操作6:释放强引用

  s1.reset

  发生条件:1.对shared_ptr做reset。2.见“一些组合操作”

  执行过程:

  s1.ptr=NULL

  s1.rep=NULL

  f(s1.rep->原子操作uses-1并返回新的值==0){

  对s1的rep额外执行一次释放弱引用操作;

  释放对象s1.ptr;

  }

  // 如果uses为0,weaks计数等于实际弱引用数,如果uses不为0,weaks计数等于实际弱引用数+1。因此如果users不为0则weaks至少为1。

  操作7:一些组合操作和例子

  此时,s2=s3=w2=(a,&c1); c1=(u:2,w:2)

  操作:s2.reset(b);

  相当于执行“强引用释放操作”: s2.reset,然后再执行“从裸指针初始化”操作 s2.reset(b)

  操作完成后,此时:

  s3=w2=(a,&c1); c1=(u:1,w:2); s2=(b,&c2);c2=(u:1,w:1)

  操作:s3=s2

  相当于执行“强引用释放操作”: s3.reset,然后执行“从强引用构造智能指针”操作:s3=s2

  此时

  w2=(a,&c1); c1=(u:0,w:1);s1=s2=(b,&c2);c2=(u:2,w:1)

  注意:s3.reset的过程中,因为c1的uses减为0。所以 delete a操作被执行,c1的weaks被额外-1。此时w2的ptr值依然等于指针a,但是delete a已经被执行,所以ptr=a是个野指针。但我们不会访问到这个野指针,因为“从弱引用构造强引用”这个操作会检查uses的计数,并抛出bad_weak_ptr异常。

  操作:w2.reset

  这个操作是释放弱引用。举这个例子是想说,c1的weaks计数只剩下1了,此时执行这个操作将使c1的weaks计数减为酚醛保温板制作工艺0并释放c1。也标志着所有指向a的强/弱引用全部释放完毕。正如我反复强调的一样,如果uses不为0,即强引用不为0,则weaks计数至少为1。weaks为0则强弱引用的数量必然都为0。

  另外,考虑一种情况。设此时有 w1=(a,&c1); c1=(u:0,w:1);w2=(NULL,NULL)

  如果一个线程p1执行w1.reset 。同时线程p2执行w2=w1

  这是不安全的。考虑下面这种执行顺序

  p2: w2=w1 执行至 检查完成w1的rep非空,但是尚未执行引用计数的增加。

  p1:w1.reset 完全执行,此时weaks计数归0,w1将rep所指向的c1释放。

  p2:w2=w1 继续执行。它将使用野指针w1.rep执行引用计数+1操作,并复制野指针rep和ptr。

  当p1线程写w1时,p2读了w1。这是犯规的。智能指针的线程安全性仅限于:

  多线程持有不同的智能指针对象,此时并发的操作这些对象是线程安全的。即使他们引用的计数器对象是同一个。

  多线程并发的读同一个智能指针对象是安全的。

  当一个线程正在修改一个智能指针对象时,其他线程对这个智能指针进行读和写都是不安全的。

  主要操作的执行过程就讲完了。




这是酚醛发泡保温板厂家 16:28:12)

评论(0)