您的位置:首页 > 其它

针对项目中同步队列死锁的解决方案

2014-08-26 16:48 489 查看
好久没有写blog了,一来没时间,二来嘛,懒!(这是主要原因)。今天遇到一个很有意思的问题,目前已经解决了,供有相同困境的同仁参考啊!在维护公司的一个有着三年历史的项目的时候,发现了一个很诡异的现象,每次调用开台、检查客位、档案更新等其他接口的时候,webclient客户端均能正常反应,网络信号较差的时候,设置的网络超时机制也可以恰到好处的起到他的作用。唯独提交菜品调用加单接口的时候,会出现服务器端已经显示加单成功,并且开始调用打印机开始打印账单了,而我们可怜的iPad上面均要死不活的出现着一个警告框:“正在提交中,请稍后。。。”

更糟糕的是,为了防止我在调用提交的时候,客户会操作UI,因此我将调用加单接口放进了主线程中,so,程序和死机了没什么两样,一直会保持这个界面,而食客什么也做不了。。悲催啊。。

   刚开始,我以为是警告框的问题在作祟,因此我再次设置了一个计时器,当警告框每节操的停留太久的时候,我会调用方法强制把他请走!但是问题又来了!没了这货,客户可以随意操作UI了,但是这次网络请求的生命周期并没有结束,于是更悲剧的结果诞生了:程序频繁crash掉! 

   我是这么处理收到服务器反馈的数据的: 



-(void)operation:(TCSLServiceBindingOperation *)operation completedWithResponse:(TCSLServiceBindingResponse *)response
{
if(response.error != NULL)
{
[self performSelectorOnMainThread:@selector(reTry) withObject:nil waitUntilDone:YES];
}else
{
[self dismissAlertView];
//[self performSelectorOnMainThread:@selector(dismissAlertView) withObject:nil waitUntilDone:YES];

for (id mine in response.bodyParts)
{
if([mine isKindOfClass:[TCSLService_TCSLService___RequestResponse class]])
{
TCSLService_TCSLService___RequestResponse *res =(TCSLService_TCSLService___RequestResponse *)mine;
[iBus ResponseXML:res.AResponseXML];
}
}

if ([self.delegate respondsToSelector:@selector(netWork
b1ba
TransOnSuccess)]) {
[self.delegate netWorkTransOnSuccess];
}
}
}
    回调方法:



// 网络传输成功返回委托实现
- (void) netWorkTransOnSuccess{
switch (Bus_Type) {
case BUS_CODE_CHECKUSER:
{
if (self.business_Request.Sucess) {
Bus_Type=BUS_CODE_CHECKTABLE;
[self.business_Request CheckOpenTable:edtTableCode.text];
}else{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:self.business_Request.Msg delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alertView setTag:-1];
[alertView show];
[alertView release];
}

break;
}
case BUS_CODE_CHECKTABLE:
{
if (self.business_Request.Sucess) {
//如果查询客位状态成功
APDocument *doc = [APDocument documentWithXMLString:self.business_Request.XML];

APElement *root = [doc rootElement];
int tableStatus = [[root valueForAttributeNamed:@"PointStatus"] intValue];
NSString *upDateTime = [root valueForAttributeNamed:@"LastTime"];
[self.tcSystem w_UpdateTime:upDateTime]; //记录上次更新的时间

if (tableStatus==3) { //如果是占用状态
//执行加单操作
if (itemOrder.bLock) {
NSString *str=[NSString stringWithFormat:@"当前菜单 %@ 已经提交过,确定要提交该菜单吗?\r\n如果在上次提交时服务器端已经完成加单操作,本次提交以及菜品的更改将不会生效。",itemOrder.OrderNO];
UIAlertView *alterView = [[UIAlertView alloc]initWithTitle:@"警告" message:str delegate:self cancelButtonTitle:@"提交" otherButtonTitles: nil];
alterView.tag = 2;
[alterView show];
[alterView release];
}else{
[itemOrder lock];
[self performSelector:@selector(submitOrder) withObject:nil afterDelay:2.0f];
//                        Bus_Type=BUS_CODE_SUBMIT;
//                         [self.business_Request AddOrder:[xml description]];
}
}
else{ //如果不是占用状态,则不能进行加单操作
NSString * msg = [self getTableState:tableStatus];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"抱歉" message:msg delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil];
[alertView show];
[alertView release];
return;
}

}else{ //如果接收程序没有回应
NSString *msg = self.business_Request.Msg;
//NSString * msg = @"查询客位状态失败!是否再次尝试?";
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"抱歉" message:msg delegate:self cancelButtonTitle:@"重试" otherButtonTitles:@"取消",nil];
alertView.tag=TAG_CHECK_TABLE;
[alertView show];
[alertView release];
return;
}
break;
}
case BUS_CODE_SUBMIT:
{
//菜品提交返回成功
[alertMsgView setMessage:self.business_Request.Msg];

if (self.business_Request.Sucess) {
[alertMsgView setTag:1];
//保存本次加单的时间
[self.tcSystem w_SubmitTime:[self getCurrentTime]];

} else {
[alertMsgView setTag:-1];
}
[alertMsgView show];
break;
}
default:
break;
}
}


    问题在哪呢?经过我多次调试,发现了一个很有趣的现象,这个现象特别隐秘,因此很不容易发现。因为调用加单接口的时候,需要首先调用客位状态的接口,当收到客位状态接口返回值为1(占用)的时候,就会立刻发起加单的网络请求。但是此时,调用客位状态接口的request释放了吗?他的生命周期走到头了吗?答案是不一定的,有时候会走完,有时候会走不完,并且走不完的概率大约为1%。测试的GGMM也辛苦了啊,点击100次可能有那么一次出现上面宕机的问题,相当考验人的耐心哦!

  OK,既然发现了问题,我想了三种处理方式,目前只是采用了其中的一种,现在经过回归测试,没有再现这个宕机的问题,谢天谢地啊!方式1:修改服务器端的加单接口,将检查客位状态的接口与加单接口整合,这个方法很麻烦,需要服务器端的人配合,但是一劳永逸; 方式二:(我目前采用的)
采取延时操作,当收到客位状态的时候,不是立马发送加单请求,而是停留2秒的时间再发送,经过我的研究,2秒钟足够调用十多次检查客位状态的接口了!因此能够解决我的困境; 方式三:加状态值进行判断,如果检查客位状态的接口回调方法结束之后,设置一个状态为YES,当状态为YES的时候才发起网络请求。此方法有缺陷,因为虽然回调方法走完了,但是request有没有Over我也不知道。但是作为一个备用思路未尝不是一个好的解决方案。


     好了。就此停笔。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐