1、使用操作系统提供的API来实现。
setjmp、longjmp 这两个函数本身线程安全的
goto 在一个函数栈内跳转,短跳。
longjmp 可以跨越函数的跳转、函数之间的跳转。
//try catch -->setjmp longjmp
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
int count = 0;
typedef truct _Exception
{
jmp_buf env;
int exceptype;
}Exception;
#define try(excep) if ((excep.exceptype = setjmp(excep.env)) == 0)
void sub_func(int idx)//该函数的栈会被覆盖,不会栈溢出
{
printf("sub_fuc-->idx:%d\n",idx);
longjmp(env,idx);//跳转到标签位 //throw
}
int main()
{
int idx = 0;
count = setjmp(env);//设置标签位,首次返回0,其它次返回longjmp带过来的值
if (count == 0)//try
{
printf("count:%d\n",count);
sub_func(++idx);
}
else if(count == 1)//catch(1)
{
printf("count:%d\n",count);
sub_func(++idx);
}
else if(count == 2)//catch(2)
{
printf("count:%d\n",count);
sub_func(++idx);
}
else if(count == 3)//catch(3)
{
printf("count:%d\n",count);
sub_func(++idx);
}
else
{
printf("other count\n");
}
{//finally
}
return 0;
}
try --->setjmp
throw -->longjmp
//try catch -->setjmp longjmp
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
int count = 0;
typedef truct _Exception
{
jmp_buf env;
int exceptype;
}Exception;
#define Try(excep) if ((excep.exceptype = setjmp(excep.env)) == 0)
#define Catch(excep,ExcepType) else if(excep.exceptype == ExcepType)
#define Throw(excep,ExcepType) longjmp(excep.env,ExcepType)
#define Finally
void throw_func(Exception ex, int idx)//该函数的栈会被覆盖,不会栈溢出
{
printf("throw_func-->idx:%d\n",idx);
Throw(ex,idx);
}
int main()
{
int idx = 0;
Exception ex;
Try(ex)
{
printf("idx:%d\n",idx);
throw_func(ex,++idx);
}
Catch(ex,1)
{
printf("count:%d\n",ex.exceptype);
}
Catch(ex,2)
{
printf("count:%d\n",ex.exceptype);
}
Catch(ex,3)
{
printf("count:%d\n",ex.exceptype);
}
Finally
{
printf("Finally\n");
}
return 0;
}
2、try/catch 嵌套如何解决
和栈先进后出,后进先出概念一样,使用
每一层try都对应一个setjmp,即对应一个jmp_buf
try过程是一个入栈过程,
throw是出栈过程,
try
{
try
{
try
{}
catch()
{}
}
catch()
{
}
}
catch()
{
}
3、抛出异常时,常带有的信息有在哪个文件,行号,函数名。
_FILE_
_LINE_
_func_
4、多线程同时操作,线程安全try/catch如何保证,线程的私有空间
//try catch -->setjmp longjmp
#include <stdio.h>
#include <setjmp.h>
Exception *header;
//pthread_key_t //线程的私有空间,每个线程都有一份,虽然每个线程内的key名字,但是值不一样
#define ThreadLocalData pthread_key_t
#define ThreadLocalDataSet(key,value) pthread_setspecific((key),(value))
#define ThreadLocalDataGet(key,value) pthread_getspecific((key))
#define ThreadLocalDataCreate(key,value) pthread_createspecific((key),(value))
#define EXCEPTION_MASSAGE_LENGTH 512
ThreadLocalData ExceptionStack;
typedef truct _Exception
{
jmp_buf env;
int exceptype;
struct _Exception *next; //单向链表,头插法,实现栈
char msg[EXCEPTION_MASSAGE_LENGTH];
}Exception;
enum{
ExceptionEntered = 0,
ExceptionThrown,
ExceptionHandled,
ExceptionFinalized,
}
#define Try do{\
Exception excep;\
excep->next = ThreadLocalDataGet(ExceptionStack);\ //获取栈顶
ThreadLocalDataSet(ExceptionStack, &excep);\ //设置新节点为栈顶
int Exception_flag = setjmp(excep.env);
if (Exception_flag == ExceptionEntered){
#define Catch
#define Finally
void ExceptionThrow(Exception , const char *func, const char *file, int line,
const char *cause, ...)
{
Exception excep = ThreadLocalDataGet(ExceptionStack);
ThreadLocalDataSet(ExceptionStack, excep->next);//出栈
if (excep)
{
va_list ap;
va_start(ap, cause);
vsprintf(excep.msg, EXCEPTION_MASSAGE_LENGTH,cause,ap);
va_end(ap);
longjmp(excep.env,ExceptionThrown);
}
}
void throw_func(Exception ex, int idx)//该函数的栈会被覆盖,不会栈溢出
{
printf("throw_func-->idx:%d\n",idx);
ExceptionThrow( );
}
int main()
{
int idx = 0;
Exception ex;
Try
{
printf("idx:%d\n",idx);
throw_func(ex,++idx);
}
Catch
{
printf("count:%d\n",ex.exceptype);
}
Catch
{
printf("count:%d\n",ex.exceptype);
}
Catch
{
printf("count:%d\n",ex.exceptype);
}
Finally
{
printf("Finally\n");
}
return 0;
}