免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wheniwasyoung
打印 上一主题 下一主题

C++写后台程序时,是否不提倡try...catch... [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
41 [报告]
发表于 2010-02-03 23:39 |只看该作者
回复 40# 群雄逐鹿中原
这么夸张? 能详细说说么?

嵌套也行的吧, <<c interfaces and implementations>>中就有一个实现。
如果加上tss和类似pthread_cleanup_push那样的机制, 还是可以用用的。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
42 [报告]
发表于 2010-02-03 23:48 |只看该作者
回复  群雄逐鹿中原
这么夸张? 能详细说说么?

嵌套也行的吧, 中就有一个实现。
如果加上tss和类似 ...
OwnWaterloo 发表于 2010-02-03 23:39


就是访问硬件的一些代码,很多地方有忙等设备状态,直到设备就绪。
最外层的程序希望不管发生什么情况,都能在有限的时间退出。
于是忙等的地方,改成超时直接longjmp。最外层setjmp抓出异常。(好在整个程序纯C,没有资源分配)
如果用返回值改工作量太大,而且要判断返回值避免不正确的操作。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
43 [报告]
发表于 2010-02-03 23:59 |只看该作者
回复 41# OwnWaterloo

嵌套有点小麻烦,需要确定longjmp跳到哪一层的setjmp,
不知道c interfaces and implementations怎么实现的呢

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
44 [报告]
发表于 2010-02-04 00:00 |只看该作者
回复 42# 群雄逐鹿中原
顶~ 许多技术(技巧)本身是没错的, 就是要区分场合~

一味的赞扬或贬低没什么意义, 只会显得自己目光短浅~

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
45 [报告]
发表于 2010-02-04 00:17 |只看该作者
本帖最后由 OwnWaterloo 于 2010-02-04 00:20 编辑

回复 43# 群雄逐鹿中原

其实 …… 将jmp_buf作为一个参数传递……  应该就可以了……

  1. 如果f需要建立一个恢复点:
  2. void f(..., jmp_buf caller_env ) {

  3.       int state;
  4.       jmp_buf new_env;
  5.       if (state== setjmp( new_env ), state==0 ) { // 正常路径
  6.             并且将new_env传递给callee:
  7.             f_callee( ..., new_env );

  8.       } else {  // 异常路径
  9.             回滚一些状态
  10.             如果需要处理, 检查state。
  11.             如果不需要处理, 或者处理了也需要继续上抛:
  12.             longjmp(caller_env, new_state);
  13.       }
  14. }
复制代码

  1. 如果g不需要建立恢复点:
  2. void g( ..., jmp_buf caller_env ) {

  3.       有问题直接:
  4.       longjmp(caller_env, state);

  5.       或者将caller_env直接传递给g的callee:
  6.       g_callee( caller_env);
  7. }
复制代码
这样对函数签名的侵入较大……  所以cii好像(具体记不太清楚了)将各个frame中的jmp_buf组成一个链表, 有个全局的链表头作为栈顶。
struct frame {
      jmp_buf env;
      struct frame* next;
}* g_top;

void f(void) {
      frame restore_point;
      restore_point.next = g_top;
      g_top = &restore_point;
      ...
      if ( setjmp( g_top->env ) ... )
}

遵循这么一个惯例 —— g_top->env 当作最近一个恢复点(当然,还有恢复的代码没写……) —— 对函数签名就没有侵入性了。 代码可能有错, 大致就是这个意思………………
如果将全局g_top的改为tss, 基本就可用了。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
46 [报告]
发表于 2010-02-04 00:39 |只看该作者
回复 45# OwnWaterloo

你真有才!这个办法可行!jmp_buf使用到完美,不多不少还不是全局的!
非常感谢!

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
47 [报告]
发表于 2010-02-04 00:56 |只看该作者
回复 46# 群雄逐鹿中原
没…… 还是有用错的地方…… 严格的说…… 侵入式的签名中, 应该是:

void f( ..., jmp_buf* caller_env );
搭配的throw是: longjmp( *caller_env );
搭配的try块是: f_callee( &new_env );

如果将jmp_buf按值传递就存在对jmp_buf实现方式的假设,也许会有问题。
虽然, 根据setjmp(env)的调用语法几乎可以推断这种假设一定成立 …… 还是保守一点好, 没必要去多依赖一个假设。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
48 [报告]
发表于 2010-02-04 01:26 |只看该作者
本帖最后由 群雄逐鹿中原 于 2010-02-04 01:55 编辑
回复  群雄逐鹿中原
没…… 还是有用错的地方…… 严格的说…… 侵入式的签名中, 应该是:

void f( . ...
OwnWaterloo 发表于 2010-02-04 00:56


用第二个直接g_top传递,没有问题的。
拿你的代码改了一个
  1. #include <setjmp.h>
  2. #include <stdio.h>

  3. struct try_env
  4. {
  5.     jmp_buf    env;
  6.     int        err;
  7.     struct try_env *next;
  8. } *g_try_top;




  9. #define TRY(try_env)    if                                           \
  10. (                                                                    \
  11.     try_env.next = g_try_top,                                        \
  12.     g_try_top = &try_env,                                            \
  13.     ( g_try_top->err = setjmp( g_try_top->env ) ) == 0                 \
  14. )
  15. #define CATCH()            else if( g_try_top = g_try_top->next , 1 )
  16. #define THROW(err)        longjmp( g_try_top->env, ( err ) )



  17. void func( )
  18. {
  19.     THROW( __LINE__ );
  20. }


  21. int main( )
  22. {
  23.     struct try_env env0;

  24.     TRY( env0 )
  25.     {
  26.         struct try_env env1;

  27.         TRY( env1 )
  28.         {
  29.             func( );
  30.         }
  31.         CATCH( )
  32.         {
  33.             printf( "Catch err1 = %d\n", env1.err );
  34.             THROW( env1.err * 2 );
  35.         }
  36.     }
  37.     CATCH( )
  38.     {
  39.         printf( "Catch err0 = %d\n", env0.err );
  40.     }
  41.    
  42.     return 0;
  43. }

复制代码

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
49 [报告]
发表于 2010-02-04 01:46 |只看该作者
本帖最后由 OwnWaterloo 于 2010-02-04 01:58 编辑

回复 48# 群雄逐鹿中原
找到cii在网上的代码了:
http://code.google.com/p/cii/source/browse/trunk/include/except.h
http://code.google.com/p/cii/source/browse/trunk/src/except.c

我想再添加一个功能……  有点类似pthread_cleanup_push/pop。
如果一个函数f满足 : 1. 它对异常保持中立, 2. 它需要在异常发生时, 回滚一些状态; 就可以使用这种机制, 而不需要建立一个try块, 也不需要cii中的finally。
比如:
void f(void) {
      r1_t r1 = r1_acquire();
      cexcept_push( r1, r1_release);
      work( r1 );
      cexcept_pop( 1 );
}

这样的话…… 数据结构大致就是:
try_block :
      jmp_buf evn;
      stack_of_cleanup_handler cleanup;
      other

若干try_block组成一个栈 try_stack;  每个线程独享一个try_stack
建立一个try块: try_stack.push( new try_block );
异常发生时,top = try_stack.pop();  reverse_execute( top->cleanup); longjmp( top->env );
这和C++的异常……  已经很相似了……

然后……  再把语法弄好看一些…… 比如能不能不用回调方式, 而是类似boost.scope_exit
比如:
void f( void ) {
      r1_t r1 = r1_acquire();
      cexcept_push( r1 ) {
            ...
            r1_release(r1);
            ...
      }
      work( r1 );
      cexcept_pop( 1 );
}

再看能不能弄成clean c 的……

以前觉得这东西没市场……  给C++程序员介绍异常(以及它的优势)就够累了,  C程序员……
所以就只构想了这些, 没往下做了……
好像你挺感兴趣的嘛

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
50 [报告]
发表于 2010-02-04 02:06 |只看该作者
回复 49# OwnWaterloo

所以是需要在 cexcept_push 里面回滚状态了,完全不要try块觉得有难度。
cexcept_push 和 cexcept_pop看来必须是宏的形式,一个原因setjmp正如alloca, 是一个不能重新打包成函数的东西,
二来需要在其中加入{ } 决定work() 是否运行。
期待你的奇思妙想。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP