青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 40, 文章 - 0, 評(píng)論 - 9, 引用 - 0
數(shù)據(jù)加載中……

UNIX CP命令

# 重復(fù)作兩次動(dòng)作,由于 /tmp 底下已經(jīng)存在 bashrc 了,加上 -i 參數(shù),
# 則在覆蓋前會(huì)詢問使用者是否確定!可以按下 n 或者 y 呢!
# 但是,反過來說,如果不想要詢問時(shí),則加上 -f 這個(gè)參數(shù)來強(qiáng)制直接覆蓋!

范例二:將 /var/log/wtmp 復(fù)制到 /tmp 底下
[root@linux tmp]# cp /var/log/wtmp . <==想要復(fù)制到目前的目錄,最后的 . 不要忘
[root@linux tmp]# ls -l /var/log/wtmp wtmp
-rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
-rw-r--r--  1 root root 71808 Jul 18 21:58 wtmp
# 注意到了嗎?!在不加任何參數(shù)的情況下,檔案的所屬者會(huì)改變,連權(quán)限也跟著改變了~
# 這是個(gè)很重要的特性!要注意喔!還有,連檔案建立的時(shí)間也不一樣了!
# 如果您想要將檔案的所有特性都一起復(fù)制過來,可以加上 -a 喔!
[root@linux tmp]# cp -a /var/log/wtmp wtmp_2
[root@linux tmp]# ls -l /var/log/wtmp wtmp_2
-rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
-rw-rw-r--  1 root utmp 71808 Jul 18 12:46 wtmp_2
# 瞭了吧!整個(gè)資料特性完全一模一樣ㄟ!真是不賴~這就是 -a 的特性!

范例三:復(fù)制 /etc/ 這個(gè)目錄下的所有內(nèi)容到 /tmp 底下
[root@linux tmp]# cp /etc/ /tmp
cp: omitting directory `/etc'   <== 如果是目錄,不能直接復(fù)制,要加上 -r 的參數(shù)
[root@linux tmp]# cp -r /etc/ /tmp
# 還是要再次的強(qiáng)調(diào)喔! -r 是可以復(fù)制目錄,但是,檔案與目錄的權(quán)限會(huì)被改變~
# 所以,也可以利用 cp -a /etc /tmp 來下達(dá)指令喔!

范例四:將范例一復(fù)制的 bashrc 建立一個(gè)連結(jié)檔 (symbolic link)
[root@linux tmp]# ls -l bashrc
-rw-r--r--  1 root root 395 Jul 18 22:08 bashrc
[root@linux tmp]# cp -s bashrc bashrc_slink
[root@linux tmp]# cp -l bashrc bashrc_hlink
[root@linux tmp]# ls -l bashrc*
-rw-r--r--  2 root root 395 Jul 18 22:08 bashrc
-rw-r--r--  2 root root 395 Jul 18 22:08 bashrc_hlink
lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
# 那個(gè) bashrc_slink 是由 -s 的參數(shù)造成的,建立的是一個(gè)『快捷方式』,
# 所以您會(huì)看到在檔案的最右邊,會(huì)顯示這個(gè)檔案是『連結(jié)』到哪里去的!
# 至于那個(gè) bashrc_hlink 有趣了!建立了這個(gè)檔案之后, bashrc 與 bashrc_hlink 
# 所有的參數(shù)都一樣,只是,第二欄的 link 數(shù)改變成為 2 了~而不是原本的 1 喔!
# 這兩種連結(jié)的方式的異同,我們會(huì)在下一章里面進(jìn)行介紹的!

范例五:若 ~/.bashrc 比 /tmp/bashrc 新才復(fù)制過來
[root@linux tmp]# cp -u ~/.bashrc /tmp/bashrc
# 這個(gè) -u 的特性,是在目標(biāo)檔案與來源檔案有差異時(shí),才會(huì)復(fù)制的。
# 所以,比較常被用于『備份』的工作當(dāng)中喔! ^_^

范例六:將范例四造成的 bashrc_slink 復(fù)制成為 bashrc_slink_2
[root@linux tmp]# cp bashrc_slink bashrc_slink_2
[root@linux tmp]# ls -l bashrc_slink*
lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
-rw-r--r--  1 root root 395 Jul 18 22:48 bashrc_slink_2
# 這個(gè)例子也是很有趣喔!原本復(fù)制的是連結(jié)檔,但是卻將連結(jié)檔的實(shí)際檔案復(fù)制過來了
# 也就是說,如果沒有加上任何參數(shù)時(shí),復(fù)制的是源文件,而非連結(jié)文件的屬性!
# 若要復(fù)制連結(jié)文件的屬性,就得要使用 -d 或者 -a 的參數(shù)了!

范例七:將家目錄的 .bashrc 及 .bash_history 復(fù)制到 /tmp 底下
[root@linux tmp]# cp ~/.bashrc ~/.bash_history /tmp
# 可以將多個(gè)數(shù)據(jù)一次復(fù)制到同一個(gè)目錄去!
這個(gè) cp 的功能很多,而由于我們常常在進(jìn)行一些數(shù)據(jù)的復(fù)制,所以也會(huì)常常用到這個(gè)指令的。 一般來說,我們?nèi)绻?fù)制別人的數(shù)據(jù) (當(dāng)然,該檔案您必須要有 read 的權(quán)限才行啊! ^_^) 時(shí), 總是希望復(fù)制到的數(shù)據(jù)最后是我們自己的,所以,在預(yù)設(shè)的條件中, cp 的來源檔與目的檔的權(quán)限是不同的,目的檔的擁有者通常會(huì)是指令操作者本身。舉例來說, 上面的范例二中,由于我是 root 的身份,因此復(fù)制過來的檔案擁有者與群組就改變成為 root 所有了! 這樣說,可以明白嗎?! ^_^

由于具有這個(gè)特性,因此,當(dāng)我們?cè)谶M(jìn)行備份的時(shí)候,某些需要特別注意的特殊權(quán)限檔案, 例如密碼文件 (/etc/shadow) 以及一些設(shè)定檔,就不能直接以 cp 來復(fù)制,而必須要加上 -a 或者是 -p 等等可以完整復(fù)制檔案權(quán)限的參數(shù)才行!另外,如果您想要復(fù)制檔案給其它的使用者, 也必須要注意到檔案的權(quán)限(包含讀、寫、執(zhí)行以及檔案擁有者等等), 否則,其它人還是無法針對(duì)您給予的檔案進(jìn)行修訂的動(dòng)作喔!注意注意!

至于上面的范例當(dāng)中,第四個(gè)范例是最有趣的,使用 -l 及 -s 都會(huì)建立所謂的連結(jié)檔 (link file), 但是這兩種連結(jié)檔確有不一樣的展現(xiàn)情況。這是怎么一回事啊? 那個(gè) -l 就是所謂的 hard link ,至于 -s 則是 symbolic link ,鳥哥這里先不介紹, 因?yàn)檫@個(gè)涉及 i-node 的相關(guān)知識(shí),我們還沒有介紹到,下一章再來討論這個(gè) link 的問題喔! 總之,由于 cp 有種種的檔案屬性與權(quán)限的特性,所以,在復(fù)制時(shí),您必須要清楚的了解到: 
• 是否需要完整的保留來源檔案的信息? 
• 來源檔案是否為連結(jié)檔 (symbolic link file)? 
• 來源檔是否為特殊的檔案,例如 FIFO, socket 等? 
• 來源文件是否為目錄?

posted @ 2008-01-02 11:56 茶 閱讀(8490) | 評(píng)論 (0)編輯 收藏

SQL語言簡介

     摘要: 1、           SQL概述 SQL是一種面向數(shù)據(jù)庫的通用數(shù)據(jù)處理語言規(guī)范,能完成以下幾類功能:提取查詢數(shù)據(jù),插入修改刪除數(shù)據(jù),生成修改和刪除數(shù)據(jù)庫對(duì)象,數(shù)據(jù)庫安全控制,數(shù)據(jù)庫完整性及數(shù)據(jù)保護(hù)控制。 數(shù)據(jù)庫對(duì)象包括表、視圖、索引、同義詞、簇、觸發(fā)器、函數(shù)、過程、包、數(shù)據(jù)庫鏈、快照等(表空...  閱讀全文

posted @ 2007-12-29 17:25 茶 閱讀(278) | 評(píng)論 (0)編輯 收藏

用Pro*C開發(fā)多線程應(yīng)用程序 (1)

(注:本文來自Pro*C/C++ Precompiler Programmer's Guide Release 8.1.5) 
  
  如果你的操作系統(tǒng)不支持線程,本文暫不適合你。本文包含以下幾個(gè)部分: 
  
  n 什么是多線程? 
  
  n Pro*C中的運(yùn)行時(shí)上下文 
  
  n 運(yùn)行時(shí)上下文的使用模式 
  
  n 多線程應(yīng)用程序的用戶接口 
  
  n 多線程例子 
  
  一.什么是多線程? 
  一個(gè)多線程的應(yīng)用程序中,線程運(yùn)行在共享的地址空間里。線程是在進(jìn)程內(nèi)部執(zhí)行的“輕量”級(jí)子進(jìn)程,它們共享代碼段和數(shù)據(jù)段,但是有自己的程序計(jì)數(shù)器、寄存器和堆棧。全局變量和靜態(tài)變量在線程之間是共享的,因此通常需要在程序中使用某種互斥機(jī)制來管理線程對(duì)這些變量的訪問,互斥體Mutexes就是用來保證數(shù)據(jù)完整性的同步裝置。 
  
  有關(guān)互斥體的更多討論,參看多線程編程方面的文章。 
  
  Proc*C編譯器通過以下方式支持開發(fā)多線程的Oracle應(yīng)用程序(在支持線程的平臺(tái)上): 
  
  n 用一個(gè)命令行編譯選項(xiàng)來產(chǎn)生線程安全的代碼 
  
  n 用內(nèi)嵌的SQL語句和指令支持多線程 
  
  n 線程安全的Lib庫和其他客戶端Lib庫 
  
  注意:也許你的平臺(tái)支持某個(gè)特殊的線程包,但還是需要查看Oracle有關(guān)平臺(tái)的文檔,看看Oracle是否支持它。 
  
  二.Pro*C中的運(yùn)行時(shí)上下文 
  為了在線程和數(shù)據(jù)庫連接之間建立松散的結(jié)合,Pro*C引入了一個(gè)概念runtime_context,我們稱之為運(yùn)行時(shí)上下文。一個(gè)運(yùn)行時(shí)上下文包含了以下資源和信息: 
  
  n 與數(shù)據(jù)庫服務(wù)器的連接 
  
  n 當(dāng)前連接上使用的游標(biāo) 
  
  n 內(nèi)嵌的一些選項(xiàng),如MODE,HOLD_CURSOR,RELEASE_CURSOR和 SELECT_ERROR 
  
  不僅僅是簡單的支持線程和連接之間的松散結(jié)合,Pro*C編譯器還允許開發(fā)人員在線程和運(yùn)行時(shí)上下文之間建立松散的結(jié)合,Pro*C允許在程序里為運(yùn)行時(shí)上下文定義一個(gè)句柄,通過這個(gè)句柄,運(yùn)行時(shí)上下文可以在線程之間切換。 
  
  例如,一個(gè)交互式應(yīng)用程序創(chuàng)建了線程T1,來執(zhí)行一個(gè)查詢,并且返回了前10條記錄,然后T1終止。在用戶輸入了必須的數(shù)據(jù)之后,程序又創(chuàng)建了線程T2,并且把T1使用的運(yùn)行時(shí)上下文傳給T2,這樣T2可以在同一個(gè)游標(biāo)上獲取接下來10條的記錄。 
  
  三.運(yùn)行時(shí)上下文的使用模式 
  下面是在多線程的Pro*C程序中使用運(yùn)行時(shí)上下文的兩種可能模式: 
  
  n 多線程共享單個(gè)運(yùn)行時(shí)上下文 
  
  n 多線程使用互相獨(dú)立的運(yùn)行時(shí)上下文 
  
  不管采用哪種模式,不能在同一時(shí)刻多個(gè)線程共享同一個(gè)運(yùn)行時(shí)上下文。如果兩個(gè)或兩個(gè)以上的線程在同一時(shí)刻試圖使用同一個(gè)運(yùn)行時(shí)上下文,將會(huì)出現(xiàn)以下錯(cuò)誤:SQL-02131: Runtime context in use。 
  
  1.多線程共享單個(gè)運(yùn)行時(shí)上下文 
  
  2.多線程使用互相獨(dú)立的運(yùn)行時(shí)上下文 
  
  四.多線程應(yīng)用程序的用戶接口 
  Pro*C編譯器提供以下接口來支持多線程: 
  
  n 命令行選項(xiàng),THREADS=YES|NO 
  
  n 內(nèi)嵌SQL語句和指令 
  
  n 線程安全的公共庫函數(shù) 
  
  1.THREADS選項(xiàng) 
  在proc預(yù)編譯命令行上指定THREADS=YES,Pro*C編譯器將保證產(chǎn)生的C代碼是線程安全的。如果指定了THREADS=YES,Pro*C將會(huì)檢查每個(gè)包含SQL執(zhí)行語句的函數(shù),是否指定了這些語句是在哪個(gè)運(yùn)行時(shí)上下文中執(zhí)行的,若沒有發(fā)現(xiàn)這類指定標(biāo)識(shí),編譯器就會(huì)返回錯(cuò)誤。 
  
  2.內(nèi)嵌SQL語句和指令 
  下列內(nèi)嵌的SQL語句和指令用于支持多線程和運(yùn)行時(shí)上下文的使用: 
  
  n EXEC SQL ENABLE THREADS; 
  
  n EXEC SQL CONTEXT ALLOCATE :context_var; 
  
  n EXEC SQL CONTEXT USE {:context_var/DEFAULT}; 
  
  n EXEC SQL CONTEXT FREE :context_var; 
  
  在以上SQL語句中,context_var是運(yùn)行時(shí)上下文句柄,它必須被定義成sql_context類型:如sql_context context_var; 
  
  使用DEFAULT意味著接下來的SQL語句將使用默認(rèn)的全局運(yùn)行時(shí)上下文,直到另一條CONTEXT USE語句覆蓋它。 
  
  n EXEC SQL ENABLE THREADS 
  
  這條可執(zhí)行SQL語句初始化支持多線程的進(jìn)程。它必須是程序中第一條可執(zhí)行的SQL語句。 
  
  n EXEC SQL CONTEXT ALLOCATE 
  
  這條可執(zhí)行SQL語句分配并初始化了一塊用于指向一個(gè)新的運(yùn)行時(shí)上下文的內(nèi)存,并返回標(biāo)識(shí)該上下文的句柄變量,該變量必須聲明為sql_context類型。 
  
  n EXEC SQL CONTEXT USE 
  
  這條指令性語句告訴編譯器接下去執(zhí)行的SQL語句將使用指定的運(yùn)行時(shí)上下文,這里的運(yùn)行時(shí)上下文必須在此前已經(jīng)用CONTEXT ALLOCATE分配并初始化。 
  
  n EXEC SQL CONTEXT FREE 
  
  這條語句釋放了運(yùn)行時(shí)上下文句柄指定的內(nèi)存,并把它設(shè)置空值。 
  
  3.編程時(shí)要考慮的問題 
  盡管Oracle保證SQL庫是線程安全的,但是你還是有責(zé)任保證你的Pro*C代碼是為能在多線程下正確運(yùn)行而設(shè)計(jì)的,例如,你必須考慮全局變量和靜態(tài)變量的。 
  
  另外,多線程要求對(duì)以下問題進(jìn)行考慮: 
  
  n 把sqlca結(jié)構(gòu)定義成線程安全的。典型的做法是在每個(gè)函數(shù)開始定義一個(gè)同名的局部變量。 
  
  n sqlda結(jié)構(gòu)也和sqlca結(jié)構(gòu)一樣處理。 
  
  n 把程序里的宿主變量定義成線程安全的。也就是說要小心處理程序里的全局變量和靜態(tài)變量。 
  
  n 避免同一時(shí)刻不同線程使用同一個(gè)運(yùn)行時(shí)上下文。 
  
  五.多線程例子 
  下面的例子運(yùn)行在Red Hat9和Oracle9上。程序目的是用兩個(gè)線程同時(shí)往一個(gè)表里插10000條記錄,每個(gè)線程都擁有自己的運(yùn)行時(shí)上下文。 
  
  #include 
  
  #include 
  
  #include /* Linux線程
  • 頭文件 */ 
      
      #include "sqlca.h" /* Oracle頭文件 */ 
      
      #define SQLCODE sqlca.sqlcode 
      
      static int insert_data( sql_context ); 
      
      static int start(); 
      
      int 
      
      main() 
      
      { 
      
      pthread_t tid1, tid2; 
      
      /* 創(chuàng)建兩個(gè)線程 */ 
      
      if( pthread_create( &tid1,NULL,(void *)start,NULL ) ){ 
      
      printf( "創(chuàng)建線程失敗!\n" ); 
      
      exit(1); 
      
      } 
      
      if( pthread_create( &tid2,NULL,(void *)start,NULL ) ){ 
      
      printf( "創(chuàng)建線程失敗!\n" ); 
      
      exit(1); 
      
      } 
      
      /* 等待線程退出 */ 
      
      if( pthread_join( tid1,NULL ) ){ 
      
      printf( "等待線程結(jié)束失敗!\n" ); 
      
      exit(1); 
      
      } 
      
      if( pthread_join( tid2,NULL ) ){ 
      
      printf( "等待線程結(jié)束失敗!\n" ); 
      
      exit(1); 
      
      } 
      
      exit(0); 
      
      } 
      
      
      int 
      
      start() 
      
      { 
      
      sql_context context; 
      
      struct sqlca sqlca; /* 需要在此定義一個(gè)局部的sqlca */ 
      
      char uid[] = "dev/888888"; 
      /* 以下SQL語句的執(zhí)行順序不能更改 */ 
      
      EXEC SQL ENABLE THREADS; 
      
      EXEC SQL CONTEXT ALLOCATE :context; 
      
      EXEC SQL CONTEXT USE :context; 
      
      EXEC SQL CONNECT :uid; 
      
      if( SQLCODE < 0 ){ 
      
      printf( "創(chuàng)建數(shù)據(jù)庫連接失敗,%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc); 
      
      return -1; 
      
      }insert_data( context ); 
      
      EXEC SQL COMMIT WORK RELEASE; 
      
      if( SQLCODE < 0 ){ 
      
      printf( "斷開數(shù)據(jù)庫連接失敗!%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc ); 
      
      return -1; 
      
      } 
      
      EXEC SQL CONTEXT FREE :context; 
      
      return 0; 
      
      } 
      
      static int 
      
      insert_data( context ) 
      
      sql_context context; 
      
      { 
      
      struct sqlca sqlca; /* 需要在此定義一個(gè)局部的sqlca */ 
      
      char name[11]; 
      
      int age; 
      
      int i; 
      
      strcpy( name, "test" ); 
      
      age = 20; 
      
      
      
      EXEC SQL CONTEXT USE :context; /* 指定執(zhí)行SQL語句的上下文 */ 
      
      for( i=0; i
  • posted @ 2007-12-29 16:23 茶 閱讀(306) | 評(píng)論 (0)編輯 收藏

    typedef

     
    typedef用法小結(jié)- -
    這兩天在看程序的時(shí)候,發(fā)現(xiàn)很多地方都用到typedef,在結(jié)構(gòu)體定義,還有一些數(shù)組等地方都大量的用到.但是有些地方還不是很清楚,今天下午,就想好好研究一下.上網(wǎng)搜了一下,有不少資料.歸納一下:
    來源一:Using typedef to Curb Miscreant Code
    Typedef 聲明有助于創(chuàng)建平臺(tái)無關(guān)類型,甚至能隱藏復(fù)雜和難以理解的語法。不管怎樣,使用 typedef 能為代碼帶來意想不到的好處,通過本文你可以學(xué)習(xí)用 typedef 避免缺欠,從而使代碼更健壯。
    typedef 聲明,簡稱 typedef,為現(xiàn)有類型創(chuàng)建一個(gè)新的名字。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼。所謂美觀,意指 typedef 能隱藏笨拙的語法構(gòu)造以及平臺(tái)相關(guān)的數(shù)據(jù)類型,從而增強(qiáng)可移植性和以及未來的可維護(hù)性。本文下面將竭盡全力來揭示 typedef 強(qiáng)大功能以及如何避免一些常見的陷阱。
    如何創(chuàng)建平臺(tái)無關(guān)的數(shù)據(jù)類型,隱藏笨拙且難以理解的語法?
    使用 typedefs 為現(xiàn)有類型創(chuàng)建同義字。
    定義易于記憶的類型名
      typedef 使用最多的地方是創(chuàng)建易于記憶的類型名,用它來歸檔程序員的意圖。類型出現(xiàn)在所聲明的變量名字中,位于 ''typedef'' 關(guān)鍵字右邊。例如:
    typedef int size;
      此聲明定義了一個(gè) int 的同義字,名字為 size。注意 typedef 并不創(chuàng)建新的類型。它僅僅為現(xiàn)有類型添加一個(gè)同義字。你可以在任何需要 int 的上下文中使用 size:
    void measure(size * psz);
    size array[4];
    size len = file.getlength();
    std::vector vs;
      typedef 還可以掩飾符合類型,如指針和數(shù)組。例如,你不用象下面這樣重復(fù)定義有 81 個(gè)字符元素的數(shù)組:
    char line[81];
    char text[81];
    定義一個(gè) typedef,每當(dāng)要用到相同類型和大小的數(shù)組時(shí),可以這樣:
    typedef char Line[81];
    Line text, secondline;
    getline(text);
    同樣,可以象下面這樣隱藏指針語法:
    typedef char * pstr;
    int mystrcmp(pstr, pstr);
      這里將帶我們到達(dá)第一個(gè) typedef 陷阱。標(biāo)準(zhǔn)函數(shù) strcmp()有兩個(gè)‘const char *'類型的參數(shù)。因此,它可能會(huì)誤導(dǎo)人們象下面這樣聲明 mystrcmp():
    int mystrcmp(const pstr, const pstr);
      這是錯(cuò)誤的,按照順序,‘const pstr'被解釋為‘char * const'(一個(gè)指向 char 的常量指針),而不是‘const char *'(指向常量 char 的指針)。這個(gè)問題很容易解決:
    typedef const char * cpstr;
    int mystrcmp(cpstr, cpstr); // 現(xiàn)在是正確的
    記住:不管什么時(shí)候,只要為指針聲明 typedef,那么都要在最終的 typedef 名稱中加一個(gè) const,以使得該指針本身是常量,而不是對(duì)象。
    代碼簡化
      上面討論的 typedef 行為有點(diǎn)像 #define 宏,用其實(shí)際類型替代同義字。不同點(diǎn)是 typedef 在編譯時(shí)被解釋,因此讓編譯器來應(yīng)付超越預(yù)處理器能力的文本替換。例如:
    typedef int (*PF) (const char *, const char *);
      這個(gè)聲明引入了 PF 類型作為函數(shù)指針的同義字,該函數(shù)有兩個(gè) const char * 類型的參數(shù)以及一個(gè) int 類型的返回值。如果要使用下列形式的函數(shù)聲明,那么上述這個(gè) typedef 是不可或缺的:
    PF Register(PF pf);
      Register() 的參數(shù)是一個(gè) PF 類型的回調(diào)函數(shù),返回某個(gè)函數(shù)的地址,其署名與先前注冊(cè)的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我們是如何實(shí)現(xiàn)這個(gè)聲明的:
    int (*Register (int (*pf)(const char *, const char *)))
    (const char *, const char *);
      很少有程序員理解它是什么意思,更不用說這種費(fèi)解的代碼所帶來的出錯(cuò)風(fēng)險(xiǎn)了。顯然,這里使用 typedef 不是一種特權(quán),而是一種必需。持懷疑態(tài)度的人可能會(huì)問:"OK,有人還會(huì)寫這樣的代碼嗎?",快速瀏覽一下揭示 signal()函數(shù)的頭文件 ,一個(gè)有同樣接口的函數(shù)。
    typedef 和存儲(chǔ)類關(guān)鍵字(storage class specifier)
      這種說法是不是有點(diǎn)令人驚訝,typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個(gè)存儲(chǔ)類關(guān)鍵字。這并是說 typedef 會(huì)真正影響對(duì)象的存儲(chǔ)特性;它只是說在語句構(gòu)成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。下面將帶到第二個(gè)陷阱:
    typedef register int FAST_COUNTER; // 錯(cuò)誤
      編譯通不過。問題出在你不能在聲明中有多個(gè)存儲(chǔ)類關(guān)鍵字。因?yàn)榉?hào) typedef 已經(jīng)占據(jù)了存儲(chǔ)類關(guān)鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲(chǔ)類關(guān)鍵字)。
    促進(jìn)跨平臺(tái)開發(fā)
      typedef 有另外一個(gè)重要的用途,那就是定義機(jī)器無關(guān)的類型,例如,你可以定義一個(gè)叫 REAL 的浮點(diǎn)類型,在目標(biāo)機(jī)器上它可以i獲得最高的精度:
    typedef long double REAL;
    在不支持 long double 的機(jī)器上,該 typedef 看起來會(huì)是下面這樣:
    typedef double REAL;
    并且,在連 double 都不支持的機(jī)器上,該 typedef 看起來會(huì)是這樣:、
    typedef float REAL;
       你不用對(duì)源代碼做任何修改,便可以在每一種平臺(tái)上編譯這個(gè)使用 REAL 類型的應(yīng)用程序。唯一要改的是 typedef 本身。在大多數(shù)情況下,甚至這個(gè)微小的變動(dòng)完全都可以通過奇妙的條件編譯來自動(dòng)實(shí)現(xiàn)。不是嗎? 標(biāo)準(zhǔn)庫廣泛地使用 typedef 來創(chuàng)建這樣的平臺(tái)無關(guān)類型:size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 這樣的 typedef 還隱藏了長長的,難以理解的模板特化語法,例如:basic_string,allocator> 和 basic_ofstream>。
    作者簡介
      Danny Kalev 是一名通過認(rèn)證的系統(tǒng)分析師,專攻 C++ 和形式語言理論的軟件工程師。1997 年到 2000 年期間,他是 C++ 標(biāo)準(zhǔn)委員會(huì)成員。最近他以優(yōu)異成績完成了他在普通語言學(xué)研究方面的碩士論文。業(yè)余時(shí)間他喜歡聽古典音樂,閱讀維多利亞時(shí)期的文學(xué)作品,研究 Hittite、Basque 和 Irish Gaelic 這樣的自然語言。其它興趣包括考古和地理。Danny 時(shí)常到一些 C++ 論壇并定期為不同的 C++ 網(wǎng)站和雜志撰寫文章。他還在教育機(jī)構(gòu)講授程序設(shè)計(jì)語言和應(yīng)用語言課程。
    來源二:(http://www.ccfans.net/bbs/dispbbs.asp?boardid=30&;id=4455)
    C語言中typedef用法
    1. 基本解釋
      typedef為C語言的關(guān)鍵字,作用是為一種數(shù)據(jù)類型定義一個(gè)新名字。這里的數(shù)據(jù)類型包括內(nèi)部數(shù)據(jù)類型(int,char等)和自定義的數(shù)據(jù)類型(struct等)。
      在編程中使用typedef目的一般有兩個(gè),一個(gè)是給變量一個(gè)易記且意義明確的新名字,另一個(gè)是簡化一些比較復(fù)雜的類型聲明。
      至于typedef有什么微妙之處,請(qǐng)你接著看下面對(duì)幾個(gè)問題的具體闡述。
     2. typedef & 結(jié)構(gòu)的問題
      當(dāng)用下面的代碼定義一個(gè)結(jié)構(gòu)時(shí),編譯器報(bào)了一個(gè)錯(cuò)誤,為什么呢?莫非C語言不允許在結(jié)構(gòu)中包含指向它自己的指針嗎?請(qǐng)你先猜想一下,然后看下文說明:
    typedef struct tagNode
    {
     char *pItem;
     pNode pNext;
    } *pNode;
      答案與分析:
      1、typedef的最簡單使用
    typedef long byte_4;
      給已知數(shù)據(jù)類型long起個(gè)新名字,叫byte_4。
      2、 typedef與結(jié)構(gòu)結(jié)合使用
    typedef struct tagMyStruct
    {
     int iNum;
     long lLength;
    } MyStruct;
      這語句實(shí)際上完成兩個(gè)操作:
      1) 定義一個(gè)新的結(jié)構(gòu)類型
    struct tagMyStruct
    {
     int iNum;
     long lLength;
    };
      分析:tagMyStruct稱為“tag”,即“標(biāo)簽”,實(shí)際上是一個(gè)臨時(shí)名字,struct 關(guān)鍵字和tagMyStruct一起,構(gòu)成了這個(gè)結(jié)構(gòu)類型,不論是否有typedef,這個(gè)結(jié)構(gòu)都存在。
      我們可以用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對(duì)的,因?yàn)閟truct 和tagMyStruct合在一起才能表示一個(gè)結(jié)構(gòu)類型。
      2) typedef為這個(gè)新的結(jié)構(gòu)起了一個(gè)名字,叫MyStruct。
    typedef struct tagMyStruct MyStruct;
      因此,MyStruct實(shí)際上相當(dāng)于struct tagMyStruct,我們可以使用MyStruct varName來定義變量。
      答案與分析
      C語言當(dāng)然允許在結(jié)構(gòu)中包含指向它自己的指針,我們可以在建立鏈表等數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)上看到無數(shù)這樣的例子,上述代碼的根本問題在于typedef的應(yīng)用。
      根據(jù)我們上面的闡述可以知道:新結(jié)構(gòu)建立的過程中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那么在類型本身還沒有建立完成的時(shí)候,這個(gè)類型的新名字也還不存在,也就是說這個(gè)時(shí)候編譯器根本不認(rèn)識(shí)pNode。
      解決這個(gè)問題的方法有多種:
      1)、
    typedef struct tagNode
    {
     char *pItem;
     struct tagNode *pNext;
    } *pNode;
      2)、
    typedef struct tagNode *pNode;
    struct tagNode
    {
     char *pItem;
     pNode pNext;
    };
      注意:在這個(gè)例子中,你用typedef給一個(gè)還未完全聲明的類型起新名字。C語言編譯器支持這種做法。
      3)、規(guī)范做法:
    struct tagNode
    {
     char *pItem;
     struct tagNode *pNext;
    };
    typedef struct tagNode *pNode;
     3. typedef & #define的問題
      有下面兩種定義pStr數(shù)據(jù)類型的方法,兩者有什么不同?哪一種更好一點(diǎn)?
    typedef char *pStr;
    #define pStr char *;
      答案與分析:
      通常講,typedef要比#define要好,特別是在有指針的場(chǎng)合。請(qǐng)看例子:
    typedef char *pStr1;
    #define pStr2 char *;
    pStr1 s1, s2;
    pStr2 s3, s4;
      在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們所預(yù)期的指針變量,根本原因就在于#define只是簡單的字符串替換而typedef則是為一個(gè)類型起新名字。
      #define用法例子:
    #define f(x) x*x
    main( )
    {
     int a=6,b=2,c;
     c=f(a) / f(b);
     printf("%d \\n",c);
    }
      以下程序的輸出結(jié)果是: 36。
      因?yàn)槿绱嗽颍谠S多C語言編程規(guī)范中提到使用#define定義時(shí),如果定義中包含表達(dá)式,必須使用括號(hào),則上述定義應(yīng)該如下定義才對(duì):
    #define f(x) (x*x)
      當(dāng)然,如果你使用typedef就沒有這樣的問題。
      4. typedef & #define的另一例
      下面的代碼中編譯器會(huì)報(bào)一個(gè)錯(cuò)誤,你知道是哪個(gè)語句錯(cuò)了嗎?
    typedef char * pStr;
    char string[4] = "abc";
    const char *p1 = string;
    const pStr p2 = string;
    p1++;
    p2++;
      答案與分析:
      是p2++出錯(cuò)了。這個(gè)問題再一次提醒我們:typedef和#define不同,它不是簡單的文本替換。上述代碼中const pStr p2并不等于const char * p2。const pStr p2和const long x本質(zhì)上沒有區(qū)別,都是對(duì)變量進(jìn)行只讀限制,只不過此處變量p2的數(shù)據(jù)類型是我們自己定義的而不是系統(tǒng)固有類型而已。因此,const pStr p2的含義是:限定數(shù)據(jù)類型為char *的變量p2為只讀,因此p2++錯(cuò)誤。
      #define與typedef引申談
      1) #define宏定義有一個(gè)特別的長處:可以使用 #ifdef ,#ifndef等來進(jìn)行邏輯判斷,還可以使用#undef來取消定義。
      2) typedef也有一個(gè)特別的長處:它符合范圍規(guī)則,使用typedef定義的變量類型其作用范圍限制在所定義的函數(shù)或者文件內(nèi)(取決于此變量定義的位置),而宏定義則沒有這種特性。
      5. typedef & 復(fù)雜的變量聲明
      在編程實(shí)踐中,尤其是看別人代碼的時(shí)候,常常會(huì)遇到比較復(fù)雜的變量聲明,使用typedef作簡化自有其價(jià)值,比如:
      下面是三個(gè)變量的聲明,我想使用typdef分別給它們定義一個(gè)別名,請(qǐng)問該如何做?
    >1:int *(*a[5])(int, char*);
    >2:void (*b[10]) (void (*)());
    >3. doube(*)() (*pa)[9];
      答案與分析:
      對(duì)復(fù)雜變量建立一個(gè)類型別名的方法很簡單,你只要在傳統(tǒng)的變量聲明表達(dá)式里用類型名替代變量名,然后把關(guān)鍵字typedef加在該語句的開頭就行了。
    >1:int *(*a[5])(int, char*);
    //pFun是我們建的一個(gè)類型別名
    typedef int *(*pFun)(int, char*);
    //使用定義的新類型來聲明對(duì)象,等價(jià)于int* (*a[5])(int, char*);
    pFun a[5];
    >2:void (*b[10]) (void (*)());
    //首先為上面表達(dá)式藍(lán)色部分聲明一個(gè)新類型
    typedef void (*pFunParam)();
    //整體聲明一個(gè)新類型
    typedef void (*pFun)(pFunParam);
    //使用定義的新類型來聲明對(duì)象,等價(jià)于void (*b[10]) (void (*)());
    pFun b[10];
    >3. doube(*)() (*pa)[9];
    //首先為上面表達(dá)式藍(lán)色部分聲明一個(gè)新類型
    typedef double(*pFun)();
    //整體聲明一個(gè)新類型
    typedef pFun (*pFunParam)[9];
    //使用定義的新類型來聲明對(duì)象,等價(jià)于doube(*)() (*pa)[9];
    pFunParam pa;

    #define S(s) printf("%s\n", #s); s

     

    typedef struct _TS1{

        int x, y;

    } TS1, *PTS1, ***PPPTS1;  // TS1是結(jié)構(gòu)體的名稱,PTS1是結(jié)構(gòu)體指針的名稱

    // 也就是將結(jié)構(gòu)體struct _TS1 命名為TS1,

    // struct _TS1 * 命名為 PTS1

    // struct _TS1 *** 命名為 PPPTS1

     

    typedef struct { // struct后面的結(jié)構(gòu)體說明也可以去掉

        int x, y;

    } TS2, *PTS2;

     

    typedef PTS1 *PPTS1; // 定義PPTS1是指向PTS1的指針

     

    typedef struct _TTS1{

        typedef struct ITTS1 {

            int x, y;

        } iner;

        iner i;

        int x, y;

    } TTS1;

     

    //結(jié)構(gòu)體內(nèi)部的結(jié)構(gòu)體也一樣可以定義

    typedef TTS1::ITTS1 ITS1;

     

    void test_struct()

    {

        // 基本結(jié)構(gòu)體重定義的使用

        TS1 ts1 = {100, 200};

        PTS1 pts1 = &ts1; // 完全等價(jià)于TS1* pts1 = &ts1;

        PPTS1 ppts1 = &pts1; // 完全等價(jià)于TS1** ppts1 = &pts1;

        PPPTS1 pppts1 = &ppts1; // 完全等價(jià)于 TS1*** pppts1 = &ppts1;

     

        TS2 ts2 = {99, 88};

        PTS2 pts2 = &ts2;   // 完全等價(jià)于 TS2* pts2 = &ts2;

     

        TTS1 itts1 = {{110, 220}, 10, 20};

        Its1* rits1 = &itts1.i;

        ITS1* &its1 = rits1; // 等價(jià)于 TTS1::ITTS1 *its1 = &(itts1.i);

     

        printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

               "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                ts1.x, ts1.y, pts1->x, pts1->y,

                (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

        printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

            ts2.x, ts2.y, pts2->x, pts2->y);

        printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t =  (%d, %d)\n\n",

            itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

     

        S(pts1->x = 119);

        S(pts2->y = 911);

        S(its1->x = 999);

     

        printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

               "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                ts1.x, ts1.y, pts1->x, pts1->y,

                (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

        printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

            ts2.x, ts2.y, pts2->x, pts2->y);

        printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t =  (%d, %d)\n\n",

            itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

     

        S((*ppts1)->y = -9999);

        printf("ts1\t = (%d, %d)\n**ppts1\t = (%d, %d)\n\n",

            ts1.x, ts1.y, (*ppts1)->x, (*ppts1)->y);

     

        S((**pppts1)->x = -12345);

        S((***pppts1).y = -67890);

        printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

               "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                ts1.x, ts1.y, pts1->x, pts1->y,

                (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

    }

    posted @ 2007-12-25 09:33 茶 閱讀(469) | 評(píng)論 (0)編輯 收藏

    unix多進(jìn)程2

    linux下的多進(jìn)程編程(2007-5-21,11:17:55)
    什么是一個(gè)進(jìn)程?進(jìn)程這個(gè)概念是針對(duì)系統(tǒng)而不是針對(duì)用戶的,對(duì)用戶來說,他面對(duì)的概念是程序。當(dāng)用戶敲入命令執(zhí)行一個(gè)程序的時(shí)候,對(duì)系統(tǒng)而言,它將啟動(dòng)一個(gè)進(jìn)程。但和程序不同的是,在這個(gè)進(jìn)程中,系統(tǒng)可能需要再啟動(dòng)一個(gè)或多個(gè)進(jìn)程來完成獨(dú)立的多個(gè)任務(wù)。多進(jìn)程編程的主要內(nèi)容包括進(jìn)程控制和進(jìn)程間通信,在了解這些之前,我們先要簡單知道進(jìn)程的結(jié)構(gòu)。
    2.1 Linux下進(jìn)程的結(jié)構(gòu)
    Linux下一個(gè)進(jìn)程在內(nèi)存里有三部分的數(shù)據(jù),就是"代碼段"、"堆棧段"和"數(shù)據(jù)段".其實(shí)學(xué)過匯編語言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統(tǒng)的運(yùn)行。這三個(gè)部分也是構(gòu)成一個(gè)完整的執(zhí)行序列的必要的部分。
    "代碼段",顧名思義,就是存放了程序代碼的數(shù)據(jù),假如機(jī)器中有數(shù)個(gè)進(jìn)程運(yùn)行相同的一個(gè)程序nokia s40 主題下載,那么它們就可以使用相同的代碼段。"堆棧段"存放的就是子程序的返回地址、子程序的參數(shù)以及程序的局部變量。而數(shù)據(jù)段則存放程序的全局變量,常數(shù)以及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間(比如用malloc之類的函數(shù)取得的空間)。這其中有許多細(xì)節(jié)問題,這里限于篇幅就不多介紹了。系統(tǒng)如果同時(shí)運(yùn)行數(shù)個(gè)相同的程序,它們之間就不能使用同一個(gè)堆棧段和數(shù)據(jù)段。
    2.2 Linux下的進(jìn)程控制
    在傳統(tǒng)的Unix環(huán)境下,有兩個(gè)基本的操作用于創(chuàng)建和修改進(jìn)程:函數(shù)fork( )用來創(chuàng)建一個(gè)新的進(jìn)程,該進(jìn)程幾乎是當(dāng)前進(jìn)程的一個(gè)完全拷貝;函數(shù)族e(cuò)xec( )用來啟動(dòng)另外的進(jìn)程以取代當(dāng)前運(yùn)行的進(jìn)程。Linux的進(jìn)程控制和傳統(tǒng)的Unix進(jìn)程控制基本一致,只在一些細(xì)節(jié)的地方有些區(qū)別手機(jī)和絢鈴聲,例如在Linux系統(tǒng)中調(diào)用vfork和fork完全相同,而在有些版本的Unix系統(tǒng)中,vfork調(diào)用有不同的功能。由于這些差別幾乎不影響我們大多數(shù)的編程,在這里我們不予考慮。
    2.2.1 fork( )
    fork在英文中是"分叉"的意思。為什么取這個(gè)名字呢?因?yàn)橐粋€(gè)進(jìn)程在運(yùn)行中,如果使用了fork,就產(chǎn)生了另一個(gè)進(jìn)程,于是進(jìn)程就"分叉"了,所以這個(gè)名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架:
    void main(){
    int i;
    if ( fork() == 0 ) {
    /* 子進(jìn)程程序 */
    for ( i = 1; i <1000; i ++ ) printf("This is child process ");
    }
    else {
    /* 父進(jìn)程程序*/
    for ( i = 1; i <1000; i ++ ) printf("This is process process ");
    }
    }
    程序運(yùn)行后,你就能看到屏幕上交替出現(xiàn)子進(jìn)程與父進(jìn)程各打印出的一千條信息了。如果程序還在運(yùn)行中,你用ps命令就能看到系統(tǒng)中有兩個(gè)它在運(yùn)行了。 那么調(diào)用這個(gè)fork函數(shù)時(shí)發(fā)生了什么呢?fork函數(shù)啟動(dòng)一個(gè)新的進(jìn)程,前面我們說過,這個(gè)進(jìn)程幾乎是當(dāng)前進(jìn)程的一個(gè)拷貝:子進(jìn)程和父進(jìn)程使用相同的代碼段;子進(jìn)程復(fù)制父進(jìn)程的堆棧段和數(shù)據(jù)段。這樣,父進(jìn)程的所有數(shù)據(jù)都可以留給子進(jìn)程,但是,子進(jìn)程一旦開始運(yùn)行,雖然它繼承了父進(jìn)程的一切數(shù)據(jù),但實(shí)際上數(shù)據(jù)卻已經(jīng)分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數(shù)據(jù)了。它們?cè)僖换バ畔r(shí),只有通過進(jìn)程間通信來實(shí)現(xiàn),這將是我們下面的內(nèi)容。既然它們?nèi)绱讼嘞螅到y(tǒng)如何來區(qū)分它們呢?這是由函數(shù)的返回值來決定的。對(duì)于父進(jìn)程,fork函數(shù)返回了子程序的進(jìn)程號(hào),而對(duì)于子程序中興小靈通來電彩鈴,fork函數(shù)則返回零。在操作系統(tǒng)中,我們用ps函數(shù)就可以看到不同的進(jìn)程號(hào),對(duì)父進(jìn)程而言,它的進(jìn)程號(hào)是由比它更低層的系統(tǒng)調(diào)用賦予的,而對(duì)于子進(jìn)程而言,它的進(jìn)程號(hào)即是fork函數(shù)對(duì)父進(jìn)程的返回值。在程序設(shè)計(jì)中,父進(jìn)程和子進(jìn)程都要調(diào)用函數(shù)fork()下面的代碼nokia 7650 鈴聲,而我們就是利用fork()函數(shù)對(duì)父子進(jìn)程的不同返回值用if……else……語句來實(shí)現(xiàn)讓父子進(jìn)程完成不同的功能,正如我們上面舉的例子一樣。我們看到,上面例子執(zhí)行時(shí)兩條信息是交互無規(guī)則的打印出來的cect鈴聲下載,這是父子進(jìn)程獨(dú)立執(zhí)行的結(jié)果,雖然我們的代碼似乎和串行的代碼沒有什么區(qū)別。 讀者也許會(huì)問,如果一個(gè)大程序在運(yùn)行中,它的數(shù)據(jù)段和堆棧都很大,一次fork就要復(fù)制一次,那么fork的系統(tǒng)開銷不是很大嗎?其實(shí)UNIX自有其解決的辦法,大家知道,一般CPU都是以"頁"為單位來分配內(nèi)存空間的,每一個(gè)頁都是實(shí)際物理內(nèi)存的一個(gè)映像,象INTEL的CPU,其一頁在通常情況下是4086字節(jié)大小,而無論是數(shù)據(jù)段還是堆棧段都是由許多"頁"構(gòu)成的,fork函數(shù)復(fù)制這兩個(gè)段,只是"邏輯"上的,并非"物理"上的,也就是說,實(shí)際執(zhí)行fork時(shí),物理空間上兩個(gè)進(jìn)程的數(shù)據(jù)段和堆棧段都還是共享著的,當(dāng)有一個(gè)進(jìn)程寫了某個(gè)數(shù)據(jù)時(shí),這時(shí)兩個(gè)進(jìn)程之間的數(shù)據(jù)才有了區(qū)別,系統(tǒng)就將有區(qū)別的"頁"從物理上也分開。系統(tǒng)在空間上的開銷就可以達(dá)到最小。
       下面演示一個(gè)足以"搞死"Linux的小程序,其源代碼非常簡單:
      void main()
       {
         for( ; ; ) fork();
       }
      這個(gè)程序什么也不做,就是死循環(huán)地fork,其結(jié)果是程序不斷產(chǎn)生進(jìn)程,而這些進(jìn)程又不斷產(chǎn)生新的進(jìn)程,很快,系統(tǒng)的進(jìn)程就滿了,系統(tǒng)就被這么多不斷產(chǎn)生的進(jìn)程"撐死了"。當(dāng)然只要系統(tǒng)管理員預(yù)先給每個(gè)用戶設(shè)置可運(yùn)行的最大進(jìn)程數(shù),這個(gè)惡意的程序就完成不了企圖了。
       2.2.2 exec( )函數(shù)族
      下面我們來看看一個(gè)進(jìn)程如何來啟動(dòng)另一個(gè)程序的執(zhí)行。在Linux中要使用exec函數(shù)族。系統(tǒng)調(diào)用execve()對(duì)當(dāng)前進(jìn)程進(jìn)行替換,替換者為一個(gè)指定的程序,其參數(shù)包括文件名(filename)、參數(shù)列表(argv)以及環(huán)境變量(envp)。exec函數(shù)族當(dāng)然不止一個(gè),但它們大致相同,在Linux中,它們分別是:execl,execlp搞笑寶寶彩鈴,execle,execv,execve和execvp,下面我只以execlp為例,其它函數(shù)究竟與execlp有何區(qū)別,請(qǐng)通過manexec命令來了解它們的具體情況。
      一個(gè)進(jìn)程一旦調(diào)用exec類函數(shù),它本身就"死亡"了,系統(tǒng)把代碼段替換成新的程序的代碼,廢棄原有的數(shù)據(jù)段和堆棧段,并為新程序分配新的數(shù)據(jù)段與堆棧段,唯一留下的,就是進(jìn)程號(hào),也就是說,對(duì)系統(tǒng)而言,還是同一個(gè)進(jìn)程,不過已經(jīng)是另一個(gè)程序了。(不過exec類函數(shù)中有的還允許繼承環(huán)境變量之類的信息。)
      那么如果我的程序想啟動(dòng)另一程序的執(zhí)行但自己仍想繼續(xù)運(yùn)行的話,怎么辦呢?那就是結(jié)合fork與exec的使用。下面一段代碼顯示如何啟動(dòng)運(yùn)行其它程序:char command[256];
    void main()
    {
    int rtn; /*子進(jìn)程的返回?cái)?shù)值*/
    while(1) {
    /* 從終端讀取要執(zhí)行的命令 */
    printf( ">" );
    fgets( command, 256, stdin );
    command[strlen(command)-1] = 0;
    if ( fork() == 0 ) {
    /* 子進(jìn)程執(zhí)行此命令 */
    execlp( command, command );
    /* 如果exec函數(shù)返回,表明沒有正常執(zhí)行命令,打印錯(cuò)誤信息*/
    perror( command );
    exit( errorno );
    }
    else {
    /* 父進(jìn)程, 等待子進(jìn)程結(jié)束,并打印子進(jìn)程的返回值 */
    wait ( &rtn );
    printf( " child process return %d ",. rtn );
    }
    }
    }
      此程序從終端讀入命令并執(zhí)行之,執(zhí)行完成后,父進(jìn)程繼續(xù)等待從終端讀入命令。熟悉DOS和WINDOWS系統(tǒng)調(diào)用的朋友一定知道DOS/WINDOWS也有exec類函數(shù),其使用方法是類似的天津聯(lián)通鈴音下載,但DOS/WINDOWS還有spawn類函數(shù),因?yàn)镈OS是單任務(wù)的系統(tǒng),它只能將"父進(jìn)程"駐留在機(jī)器內(nèi)再執(zhí)行"子進(jìn)程",這就是spawn類的函數(shù)。WIN32已經(jīng)是多任務(wù)的系統(tǒng)了,但還保留了spawn類函數(shù),WIN32中實(shí)現(xiàn)spawn函數(shù)的方法同前述UNIX中的方法差不多,開設(shè)子進(jìn)程后父進(jìn)程等待子進(jìn)程結(jié)束后才繼續(xù)運(yùn)行。UNIX在其一開始就是多任務(wù)的系統(tǒng),所以從核心角度上講不需要spawn類函數(shù)。
      在這一節(jié)里,我們還要講講system()和popen()函數(shù)。system()函數(shù)先調(diào)用fork(),然后再調(diào)用exec()來執(zhí)行用戶的登錄shell,通過它來查找可執(zhí)行文件的命令并分析參數(shù),最后它么使用wait()函數(shù)族之一來等待子進(jìn)程的結(jié)束。函數(shù)popen()和函數(shù)system()相似,不同的是它調(diào)用pipe()函數(shù)創(chuàng)建一個(gè)管道,通過它來完成程序的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。這兩個(gè)函數(shù)是為那些不太勤快的程序員設(shè)計(jì)的,在效率和安全方面都有相當(dāng)?shù)娜毕荩诳赡艿那闆r下,應(yīng)該盡量避免。
    Linux聯(lián)盟收集整理

    http://www.allegations.com.cn/baidu/8003/982.htm

    posted @ 2007-12-18 15:41 茶 閱讀(539) | 評(píng)論 (0)編輯 收藏

    unix多進(jìn)程

         摘要: 一.多進(jìn)程程序的特點(diǎn)      由于UNIX系統(tǒng)是分時(shí)多用戶系統(tǒng), CPU按時(shí)間片分配給各個(gè)用戶使用, 而在  實(shí)質(zhì)上應(yīng)該說CPU按時(shí)間片分配給各個(gè)進(jìn)程使用, 每個(gè)進(jìn)程都有自己的運(yùn)行環(huán)境  以使得在CPU做進(jìn)程切換時(shí)不會(huì)"忘記"該進(jìn)程已計(jì)算了一半的"半成品". 以DOS  的概念...  閱讀全文

    posted @ 2007-12-18 13:35 茶 閱讀(480) | 評(píng)論 (0)編輯 收藏

    STL vector的使用

      http://www.cppreference.com/cppvector/index.html
    assign
    Syntax:
      #include <vector>
    void assign( size_type num, const TYPE& val );
    void assign( input_iterator start, input_iterator end );
    

    The assign() function either gives the current vector the values from start to end, or gives it num copies of val.

    This function will destroy the previous contents of the vector.

    For example, the following code uses assign() to put 10 copies of the integer 42 into a vector:

    vector<int> v;
     v
    .assign( 10, 42 );
     
    for( int i = 0; i < v.size(); i++ ) {
       cout
    << v[i] << " ";
     
    }
     cout
    << endl;            

    The above code displays the following output:

    42 42 42 42 42 42 42 42 42 42          

    The next example shows how assign() can be used to copy one vector to another:

    vector<int> v1;
     
    for( int i = 0; i < 10; i++ ) {
       v1
    .push_back( i );
     
    }              

     vector
    <int> v2;
     v2
    .assign( v1.begin(), v1.end() );            

     
    for( int i = 0; i < v2.size(); i++ ) {
       cout
    << v2[i] << " ";
     
    }
     cout
    << endl;            

    When run, the above code displays the following output:

    0 1 2 3 4 5 6 7 8 9     



    Vector constructors
    Syntax:
      #include <vector>
    vector();
    vector( const vector& c );
    vector( size_type num, const TYPE& val = TYPE() );
    vector( input_iterator start, input_iterator end );
    ~vector();
    

    The default vector constructor takes no arguments, creates a new instance of that vector.

    The second constructor is a default copy constructor that can be used to create a new vector that is a copy of the given vector c.

    The third constructor creates a vector with space for num objects. If val is specified, each of those objects will be given that value. For example, the following code creates a vector consisting of five copies of the integer 42:

    vector<int> v1( 5, 42 );         

    The last constructor creates a vector that is initialized to contain the elements between start and end. For example:

    // create a vector of random integers
     cout
    << "original vector: ";
     vector
    <int> v;
     
    for( int i = 0; i < 10; i++ ) {
       
    int num = (int) rand() % 10;
       cout
    << num << " ";
       v
    .push_back( num );
     
    }
     cout
    << endl;            

     
    // find the first element of v that is even
     vector
    <int>::iterator iter1 = v.begin();
     
    while( iter1 != v.end() && *iter1 % 2 != 0 ) {
       iter1
    ++;
     
    }              

     
    // find the last element of v that is even
     vector
    <int>::iterator iter2 = v.end();
     
    do {
       iter2
    --;
     
    } while( iter2 != v.begin() && *iter2 % 2 != 0 );              

     
    // only proceed if we find both numbers
     
    if( iter1 != v.end() && iter2 != v.begin() ) {
       cout
    << "first even number: " << *iter1 << ", last even number: " << *iter2 << endl;        

       cout
    << "new vector: ";
       vector
    <int> v2( iter1, iter2 );
       
    for( int i = 0; i < v2.size(); i++ ) {
         cout
    << v2[i] << " ";
       
    }
       cout
    << endl;
     
    }

    When run, this code displays the following output:

    original vector: 1 9 7 9 2 7 2 1 9 8
     first even number
    : 2, last even number: 8
     
    new vector: 2 7 2 1 9          

    All of these constructors run in linear time except the first, which runs in constant time.

    The default destructor is called when the vector should be destroyed.

     

    posted @ 2007-12-11 14:26 茶 閱讀(4065) | 評(píng)論 (2)編輯 收藏

    網(wǎng)站記錄

    http://stl.winterxy.com/ 號(hào)稱最優(yōu)秀的STL使用學(xué)習(xí)網(wǎng)站
    http://www.cppreference.com/ 英文STL使用資料參考網(wǎng)站
    http://www.uml.org.cn/oobject/Oobject-lt.asp  這玩意不通不行啊
    http://www.yesky.com/SoftChannel/72342371928702976/20031215/1753319.shtml com技術(shù)很nb的技術(shù)
    http://www.cnscn.org/

    http://www.jzxue.com/建站學(xué)

    http://www.bccn.net/Article/編程中國

    http://wenda.stx168.com/?site=yb 商問網(wǎng)

    http://topic.csdn.net/u/20081014/15/c69dd6c0-c0da-4ecf-a2c2-f0fa458bbc2a.html?seed=735903946
    失業(yè)七個(gè)月,面試六十家公司的深圳體驗(yàn)

    posted @ 2007-12-11 14:02 茶 閱讀(282) | 評(píng)論 (0)編輯 收藏

    c++ STL 容器基礎(chǔ)(一)

         摘要:   閱讀全文

    posted @ 2007-12-11 14:00 茶 閱讀(5634) | 評(píng)論 (2)編輯 收藏

    C++ STL編程入門基礎(chǔ)【簡摘】

         摘要:   閱讀全文

    posted @ 2007-12-11 11:56 茶 閱讀(685) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共4頁: 1 2 3 4 
    青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美成人网| 欧美黑人国产人伦爽爽爽| 亚洲日本视频| 国产色视频一区| 欧美三级网址| 欧美成人一区二区三区| 亚洲综合日韩中文字幕v在线| 亚洲国产导航| 久久日韩粉嫩一区二区三区| 亚洲永久免费视频| 亚洲精品一区二区三区福利| 黄网站色欧美视频| 国产精品一区二区三区久久久| 欧美激情亚洲国产| 免费不卡在线视频| 麻豆精品视频在线| 久久―日本道色综合久久| 亚洲欧美三级在线| 亚洲一区二区三区四区视频| 日韩午夜激情| 亚洲精品一区二区三区99| 欧美国产日韩视频| 欧美大片免费久久精品三p| 久久视频在线看| 久久精品二区三区| 久久精品国产第一区二区三区最新章节 | 国产精品va在线播放| 欧美精品亚洲| 欧美伦理视频网站| 欧美精品久久久久久久| 欧美成年人视频网站欧美| 久久一区二区精品| 裸体丰满少妇做受久久99精品| 久久婷婷综合激情| 狂野欧美激情性xxxx欧美| 久久精品国产99精品国产亚洲性色| 亚洲欧美日韩国产一区| 午夜精品免费视频| 性色av一区二区怡红| 欧美亚洲一区二区三区| 欧美一区二区三区男人的天堂| 香蕉久久精品日日躁夜夜躁| 亚洲欧美中文日韩在线| 欧美一级视频精品观看| 欧美一区网站| 久久乐国产精品| 久久性天堂网| 欧美高清视频| 欧美日韩一区二区三区在线看| 欧美天堂亚洲电影院在线播放 | 亚洲欧美日产图| 欧美亚洲一区二区在线| 欧美在线观看一区二区三区| 先锋影音网一区二区| 欧美在线观看视频在线 | 一二三区精品| 午夜精品99久久免费| 久久精品理论片| 欧美大成色www永久网站婷| 欧美日韩精品一区二区在线播放| 国产精品99免费看 | 亚洲老司机av| 亚洲一区二区三区久久| 久久久国产91| 亚洲福利视频在线| 亚洲午夜久久久久久久久电影院 | 欧美精品网站| 国产欧美日韩精品丝袜高跟鞋| 在线成人中文字幕| 亚洲亚洲精品三区日韩精品在线视频| 欧美一区二区私人影院日本| 农村妇女精品| 亚洲视频一二三| 久久免费视频网| 欧美日韩另类国产亚洲欧美一级| 国产乱码精品一区二区三区五月婷 | 亚洲一区自拍| 欧美91视频| 国产三级精品三级| 日韩视频在线一区| 久久国产一区| 亚洲麻豆一区| 久久久久免费| 国产精品久久久久三级| 亚洲国产91精品在线观看| 亚洲一区二区久久| 欧美 日韩 国产一区二区在线视频 | 国产精品入口日韩视频大尺度| 伊人久久大香线| 先锋影音久久| 亚洲片国产一区一级在线观看| 欧美亚洲综合久久| 欧美三区免费完整视频在线观看| 在线观看国产日韩| 欧美一区激情| 一区二区三区蜜桃网| 老色批av在线精品| 国产日韩一区| 亚洲欧美日产图| 亚洲清纯自拍| 免费在线亚洲欧美| 韩国av一区二区三区在线观看| 亚洲一区在线免费| 亚洲欧洲日本在线| 久久伊伊香蕉| 国语自产精品视频在线看8查询8 | 亚洲国产欧美一区二区三区同亚洲| 午夜精品成人在线视频| 国产精品jizz在线观看美国 | 欧美日韩1区2区3区| 亚洲福利电影| 久久尤物视频| 欧美在线播放高清精品| 国产麻豆91精品| 亚洲欧美影院| 一本色道久久综合亚洲精品不| 欧美激情一区三区| 91久久精品国产91久久性色| 另类亚洲自拍| 久久精品免费电影| 韩国自拍一区| 美女国产一区| 久久久噜噜噜久久| 尤物在线观看一区| 蜜桃av一区二区三区| 欧美中文字幕在线播放| 国产一区二区三区直播精品电影 | 久久久久久亚洲精品中文字幕| 国产亚洲欧美aaaa| 久久久久久高潮国产精品视| 香蕉av777xxx色综合一区| 国产日韩欧美黄色| 久久裸体艺术| 久久精品理论片| 亚洲电影在线免费观看| 欧美国产第二页| 欧美电影打屁股sp| 一区二区三区日韩在线观看| 日韩亚洲欧美一区| 国产精品久久综合| 久久国产精品久久久久久| 久久成人18免费观看| 亚洲国产精品va在线观看黑人| 亚洲成色777777在线观看影院| 欧美激情精品久久久久久大尺度 | 欧美在线免费视屏| 久久精品女人的天堂av| 亚洲国产婷婷综合在线精品| 91久久精品国产91久久性色| 欧美少妇一区| 久久精品国产一区二区三区免费看 | 欧美日韩精品系列| 午夜久久久久久| 久久精品1区| 亚洲美女视频在线观看| 中文av一区二区| 国产一区二区电影在线观看| 免费久久精品视频| 欧美日韩高清在线| 欧美自拍偷拍午夜视频| 久久久久免费视频| 一区二区三区不卡视频在线观看 | 亚洲国产天堂久久综合| 欧美性大战久久久久久久| 久久精品国产免费看久久精品| 久久一区国产| 亚洲一区二区在线视频| 久久精品91久久久久久再现| 亚洲欧洲日本专区| 亚洲图片激情小说| 亚洲高清不卡一区| 一本色道久久综合亚洲精品不卡| 国产性天天综合网| 亚洲国产1区| 国产日韩欧美另类| 亚洲黄色一区二区三区| 国产欧美婷婷中文| 亚洲精品国产系列| 国产亚洲精品一区二555| 亚洲精品国产系列| 狠狠爱成人网| 一区二区激情| 亚洲激情成人| 欧美在线一二三| 亚洲一区二区三区成人在线视频精品 | 91久久国产综合久久蜜月精品| 亚洲宅男天堂在线观看无病毒| 亚洲国产美女| 午夜精品一区二区三区在线播放 | 欧美不卡三区| 久久日韩粉嫩一区二区三区| 欧美色视频一区| 欧美高清视频一区二区三区在线观看| 国产精品久久99| 亚洲精品欧美精品| 亚洲国产精品成人| 欧美在线观看你懂的| 亚洲欧美一区二区激情| 欧美精品三级在线观看| 欧美成人精品激情在线观看|