接口之惑:简单&滥用

接口设计上,简单、没有二义性是必须的。但是简单,则可能带来滥用。
为什么这么说呢?先看一个例子。在vxworks里,共享资源的互斥一般可
通过信号量、锁任务(tasklock/taskunlock--禁止/使能任务调度功能)
,锁中断(intlock/intunlock--关闭/使能中断)来实现。这几个接口,
影响的程度不同,一般的编程手册(包括vxworks的帮助文档),都是建
议首先使用信号量,再就是锁任务,锁中断。但是实际上,锁任务使用的
却是最多的,锁中断一听给人的感觉就是比较高深(都中断了,硬件级别
了),一般就不怎么敢用了。下面看看这三类接口的典型用法:


一、信号量
1,创建一个信号量,pMutex = semMCreate(SEM_Q_PRIORITY,SEM_FULL)
2,进入互斥区时,先获取信号量
funcA()
{
...
semTake(pMutex, WAIT_FOREVER);
共享资源操作;
semGive(pMutex);
...
}


二、锁任务
funcA()
{
...
taskLock();
共享资源操作;
taskUnlock();
...
}


三、锁中断
funcA()
{

...
int status = intLock();
共享资源操作;
intUnlock(status);
...
}


可以看出,同样是达到互斥的情况,锁任务比信号量要容易用的多了。信
号量需要创建,并引入了一个新的类型SEMID, 需要一个全局变量来保存
这个ID值,创建时指明等待队列的类型(SEM_Q_PRIORITY、SEM_Q_FIFO)
,信号量当前状态(空、满),其他属性(优先级继承SEM_INVERSION_SAFE
),足够把人绕晕。


相反,锁任务就非常简单,想用的时候直接调用即可,召之即来
挥之即走。其内部实现也是非常简单的,任务控制块里维护了一个lock计
数,tasklock时加1,taskunlock时减1,调度器运行时,判断当前运行任
务的控制块里计数不为0,则不调度了,可以保证当前任务一直运行下去



tasklock会导致不相关的高优先级任务得不到调度,但又有多少
个人关心呢?比如任务的优先级如下:t1 > t2 = t3, t2,t3需要互斥访
问同一个共享资源,使用信号量,t1就绪时是可以抢占得到运行的,但如
果使用了tasklock,t1就绪时是没有办法得到运行的。


你可以说系统只是提供了这个机制,是使用的人错了,但系统没
有从使用的人考虑,提供的机制又如何保证使用正确呢?


问题的困难可能在于vxworks没有区分内核态和用户态,所以,
不像linux,干脆用户态就不允许调用tasklock、intlock之类的接口。(
linux内核态也有禁止抢占和关中断的接口)。所以,从linux角度,
vxworks下本来是用户态程序的,也使用了内核接口,当把这类应用程序
,移植到linux下,则需要付出更大的代价(必须把tasklock替换成信号量
互斥,而且还得仔细考虑引入了新的信号量后是否会与其他信号量造成死
锁,必须非常小心!!)。出来混总是要还的。


接口要简单,但使用者也必须仔细考量,不能滥用这个简单的接


口。
#include <iostream> using namespace std; //在类外进行前置声明 // 友元函数在类外面实现,并且都在同一个CPP文件中, //需要在前面对类和对应操作符重载函数进行前置声明。 // 同时在类内部声明的对应函数需要在参数链表前加入 "<T>"。 template <class T1, class T2> class Person; template <class T1, class T2> std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p); //类模板 类外实现 //类模板 template <class T1, class T2> class Person { public: //模板类中使用友元 //重载左移操作符,用于直接打印输出 //方法1 //template <class T1, class T2> //定要加 这句,不过这样的写法在linux不能通过 //friend std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p); //方法2在操作符后加 <T1,T2>,同时进行类前置声明 //方法1 在VS中可以便宜,但 要在Linux下会出错 friend std::ostream& operator<<<T1,T2>(std::ostream& os, Person<T1, T2>& p); Person(T1 id, T2 age); void showPerson(); private: T1 mId_; T2 mAge_; }; //声明和实现分开时,我们需要对函数的声明做特殊处理, //注意,这里类名应是Person<T1,T2> template <class T1, class T2> Person<T1, T2>::Person(T1 id, T2 age) { this->mAge_ = age; this->mId_ = id; } template <class T1, class T2> void Person<T1, T2>::showPerson() { std::cout << "id.....:" << mId_ << ",age:" << mAge_ << std::endl; } //通过重载左移操作符,用于直接打印输出 template <class T1, class T2> std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p) { std::cout << "operator--- id: " << p.mId_ << ",age:" << p.mAge_ << std::endl; return os; } //类模板在类外实现时,不要滥用友元 void testShow() { //函数模板在调用时,可以自动进行类型推导 //类模板必须显式声明 Person<int, int> person(12, 11111); //person.showPerson(); std::cout << "ddd: " << person << std::endl; } int main() { testShow(); return 0; }
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值