引用计数解决资源初始化及回收问题
1 问题背景
考虑下面这个场景:
在升级芯片固件的时候,例如CPLD芯片,在BMC没有访问CPLD的时候,CPLD和BMC的Jtag没有相连,BMC在升级CPLD的时候需要先把Jtag切到BMC侧,保证两者之间的正常通信,升级完成后需要再把Jtag切换到底座上。BMC通过Jtag升级CPLD时,其他的线程也可能通过Jtag访问CPLD。那么该如何管理这个Jtag的切换呢?
首先可以肯定的是,BMC去通过Jtag访问CPLD的时候,肯定是要先把Jtag切换到BMC侧的。但是问题是什么时候需要把Jtag切回底座上去呢?因为有可能通过硬件Jtag烧录器去烧录,这个时候就需要Jtag切换到底座。
那如果在每次使用完之后直接切换会底座上呢?同样会有问题,假如有两个线程,一个是升级线程,负责升级CPLD;另外一个线程通过Jtag获取CPLD的信息,例如CPLD IDCode等。在线程1升级CPLD的过程中,此时线程2访问CPLD,线程2访问完成后直接把Jtag切换到底座上。紧接着到线程1继续升级CPLD,但是Jtag不是在BMC上,导致无法访问到CPLD,升级失败。
2 解决方案
这个问题很C++中常遇到的智能指针的问题如出一辙。当我们在堆上new创建一个对象实例后,其他的线程可能会使用到该对象指针,那么就不能在某个线程使用完后随意销毁。一般都会使用shared_ptr智能指针,shared_ptr有个成员变量是个原子变量,通过引用计数的方式来决定是否销毁shared_ptr所管理的指针。举一反三,我们也可以通过引用计数的方式来管理Jtag。引用计数是通过原子变量的自增和自减来表示使用和释放的,当引用计数大于0,则说明有线程正在使用,不可以切换Jtag;当引用计数等于0时,则说明当前没有现成在使用,可以把引用计数切换到底座上。
int cpld_jtag_open(struct inode *inode, struct file *file)
{
/* 自增1后返回旧值,旧值为0,则切换Jtag到BMC */
if (atomic_fetch_add(1, &jtag_ref_cnt) == 0) {
// printk("Set jtag mux to BMC now!");
set_jtag_mux(SELECT_JTAG_TO_BMC);
}
return 0;
}
int cpld_jtag_release(struct inode *inode, struct file *file)
{
/* 自减后返回新值,新值为0,表示Jtag使用完成,切换Jtag到Connector */
if(atomic_dec_and_test(&jtag_ref_cnt)) {
// atomic_read(&jtag_ref_cnt);
// printk("Select Jtag to connector, ref cnt: %d\n", jtag_ref_cnt.counter);
set_jtag_mux(SELECT_JTAG_TO_CON);
}
return 0;
}
3 常用的原子变量操作
3.1 加操作
| 原型 | 说明 | 返回值 |
|---|---|---|
void atomic_inc(atomic_t *v) |
自增1 |
无 |
int atomic_inc_return(atomic_t *v) |
自增1 |
返回新值 |
int atomic_fetch_inc(atomic_t *v) |
自增1 |
返回旧值 |
void atomic_add(int i, atomic_t *v) |
自增i |
无 |
int atomic_add_return(int i, atomic_t *v) |
自增i |
返回新值 |
int atomic_fetch_add(int i, atomic_t *v) |
自增i |
返回旧值 |
bool atomic_inc_and_test(atomic_t *v) |
自增1 |
如果新值为0,返回true;否则返回false |
bool atomic_add_negative(int i, atomic_t *v) |
自增i |
如果新值为负数,返回true;否则返回false |
int atomic_fetch_add_unless(atomic_t *v, int a, int u) |
unless表示if not。如果旧值跟u不等,自增a,返回旧值;如果旧值等于 u,只返回旧值,不会进行自增操作 |
返回旧值 |
bool atomic_add_unless(atomic_t *v, int a, int u) |
如果旧值跟u不等,自增a,返回true;如果旧值等于 u,返回旧值false,不会进行自增操作 |
表示是否进行了自增 |
bool atomic_inc_not_zero(atomic_t *v) |
如果旧值不等于0,那么自增1,返回true;如果旧值等于0,返回false |
表示是否进行了自增 |
bool atomic_inc_unless_negative(atomic_t *v) |
如果旧值不是负数,那么自增1,返回true;如果旧值为负数,返回false |
表示是否进行了自增 |
3.2 减操作
| 原型 | 说明 | 返回值 |
|---|---|---|
void atomic_dec(atomic_t *v) |
自减1 |
无 |
int atomic_dec_return(atomic_t *v) |
自减1 |
返回新值 |
int atomic_fetch_dec(atomic_t *v) |
||
void atomic_sub(int i, atomic_t *v) |
自减i |
无 |
int atomic_sub_return(int i, atomic_t *v) |
自减i |
返回新值 |
int atomic_fetch_sub(int i, atomic_t *v) |
自减i |
返回旧值 |
bool atomic_sub_and_test(int i, atomic_t *v) |
自减i |
如果新值为0,返回true;否则返回false |
bool atomic_dec_and_test(atomic_t *v) |
自减1 |
如果新值为0,返回true;否则返回false |
bool atomic_dec_unless_positive(atomic_t *v) |
如果旧值不是正数(<=0),那么自减1,返回true;如果旧值是正数(>0),返回false |
表示是否进行了自减操作 |

浙公网安备 33010602011771号