av手机免费在线观看,国产女人在线视频,国产xxxx免费,捆绑调教一二三区,97影院最新理论片,色之久久综合,国产精品日韩欧美一区二区三区

php語(yǔ)言

php內(nèi)核分析之ZTS和zend-try

時(shí)間:2025-04-14 20:45:17 php語(yǔ)言 我要投稿
  • 相關(guān)推薦

php內(nèi)核分析之ZTS和zend-try

  在學(xué)習(xí)PHP的同學(xué)對(duì)內(nèi)核有沒(méi)有疑問(wèn)呢?下面是百分網(wǎng)小編精心為大家整理的php內(nèi)核分析之ZTS和zend_try,希望對(duì)大家有幫助,更多內(nèi)容請(qǐng)關(guān)注應(yīng)屆畢業(yè)生網(wǎng)!

  這里閱讀的php版本為PHP-7.1.0 RC3,閱讀代碼的平臺(tái)為linux

  我們會(huì)看到文章中有很多地方是:

  #ifdef ZTS

  # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v)

  #else

  # define CG(v) (compiler_globals.v)

  extern ZEND_API struct _zend_compiler_globals compiler_globals;

  #endif

  這里的ZTS是個(gè)什么概念呢。我們經(jīng)常使用的php都是運(yùn)行在單進(jìn)程,單線程環(huán)境,比如cgi,都是一個(gè)請(qǐng)求進(jìn)來(lái),就一個(gè)進(jìn)程為它服務(wù),當(dāng)請(qǐng)求結(jié)束了,進(jìn)程也就結(jié)束了。所以比如像全局變量,php內(nèi)核就沒(méi)有考慮多線程同時(shí)修改獲取的時(shí)候線程安全問(wèn)題。后來(lái),php漸漸也在往單進(jìn)程多線程服務(wù)器方向發(fā)展。那么這個(gè)時(shí)候,就會(huì)需要有一個(gè)層來(lái)專(zhuān)門(mén)處理線程安全問(wèn)題。這個(gè)就是TSRM(Thread Safe Resource Management)。

  但是php默認(rèn)是關(guān)閉線程安全的。在編譯的時(shí)候,你可以指定參數(shù)開(kāi)啟編譯一個(gè)線程安全版本的php。(--enable-maintainer-zts 選項(xiàng), Windows 平臺(tái)為 --enable-zts)這個(gè)就是這里的ZTS的由來(lái)。

  比如上面的例子,CG(V) 在非線程安全下獲取的是全局結(jié)構(gòu)compiler_globals結(jié)構(gòu)的v屬性,在線程安全下獲取的是通過(guò)ZEND_TSREMG方法來(lái)獲取。

  zend_try

  我們會(huì)看到zend_try_catch相關(guān)的代碼如下:

  zend_try {

  ...exec_try

  } zend_catch {

  ...exec_catch

  } zend_end_try();

  把宏展開(kāi),我們可以看到大概代碼如下:

  { \

  JMP_BUF *__orig_bailout = EG(bailout); \

  JMP_BUF __bailout; \

  \

  EG(bailout) = &__bailout; \

  if (SETJMP(__bailout)==0) {

  {

  ...exec_try

  }

  } else { \

  EG(bailout) = __orig_bailout;

  {

  ...exec_catch

  }

  } \

  EG(bailout) = __orig_bailout; \

  }

  這個(gè)是什么意思呢,需要先理解下setjmp和longjmp,這兩個(gè)函數(shù)是linux提供的方法。他們是組合起來(lái)使用的,達(dá)到協(xié)同程序的功能

  #include

  #include

  jmp_buf env;

  void foo() {

  printf("before jmp\n");

  int ret = setjmp(env);

  if(ret == 0) {

  return;

  } else {

  printf("return %d\n", ret);

  }

  printf("after jmp\n");

  }

  int main(int argc, char* argv[]) {

  foo();

  longjmp(env, 999);

  return 0;

  }

  // 輸出:

  /*

  before jmp

  return 999

  after jmp

  */

  上面的這個(gè)例子,setjmp的時(shí)候相當(dāng)于程序片段1把主動(dòng)權(quán)交出來(lái),然后執(zhí)行if(ret == 0)下面的程序,直到遇到longjmp,把執(zhí)行權(quán)還給了片段1,并且設(shè)置jmp_buf為999,片段1繼續(xù)執(zhí)行,發(fā)現(xiàn)了ret!=0,就輸出return 999。

  好了,回到這個(gè)程序:

  { \

  JMP_BUF *__orig_bailout = EG(bailout); \

  JMP_BUF __bailout; \

  \

  EG(bailout) = &__bailout; \

  if (SETJMP(__bailout)==0) {

  {

  ...exec_try

  }

  } else { \

  EG(bailout) = __orig_bailout;

  {

  ...exec_catch

  }

  } \

  EG(bailout) = __orig_bailout; \

  }

  這個(gè)程序里面的exec_try代碼段里面,在遇到錯(cuò)誤的時(shí)候,需要返回的時(shí)候,就會(huì)包含一個(gè)longjmp函數(shù)的調(diào)用。這樣,就形成了我們平時(shí)調(diào)用try...catch...finnal的功能:

  1 先保存全局變量里面的bailout

  2 使用setjmp來(lái)做跳轉(zhuǎn)執(zhí)行下面的程序

  3 執(zhí)行exec_try

  4 如果exec_try這個(gè)代碼段里面有l(wèi)ongjmp,并且longjmp返回非0(一般也確實(shí)非0),就執(zhí)行exec_catch

  5 最后,把全局變量里面的bailout恢復(fù)

  這里可能會(huì)有兩個(gè)疑惑,如果exec_try里面沒(méi)有l(wèi)ongjmp怎么辦,那就直接只執(zhí)行了exec_try,就跳過(guò)exec_catch了。這個(gè)也是標(biāo)準(zhǔn)的用setjmp和longjmp實(shí)現(xiàn)try catch的寫(xiě)法。

  這兩個(gè)的實(shí)現(xiàn)彌補(bǔ)了goto關(guān)鍵字只能在函數(shù)內(nèi)部進(jìn)行跳轉(zhuǎn)的限制。這個(gè)叫做“長(zhǎng)跳轉(zhuǎn)”。

  所以在PHP代碼中,如果你執(zhí)行的函數(shù)有可能拋出異常。不妨使用這個(gè)方式把你要執(zhí)行的程序放在里面。

【php內(nèi)核分析之ZTS和zend-try】相關(guān)文章:

php內(nèi)核分析之zval05-07

php內(nèi)核分析之?dāng)U展01-31

php內(nèi)核分析之opcode08-04

php內(nèi)核分析之zend-compile05-17

php內(nèi)核分析之do-cli05-30

php內(nèi)核分析之全局變量12-14

php內(nèi)核分析之sapi-module-struct05-23

php學(xué)習(xí)之php配置07-15

php中數(shù)字0和空值的區(qū)別分析03-08