2013年11月16日 星期六

UltraEdit的菜單欄亂碼問題

    一直以來都是用notepad++作為修改代碼的編輯器,開源並且的確很好用,但是在使用時發現一個嚴重bug,若一個文件同時被notepad++和另 外的程序打開,而另外的程序修改了這個文件,notepad++不能及時顯示,只能多點一次「重新讀取文件」的菜單,估計作者已經知道這個bug,但是程 序底層無法修改,所以就採用了這種補救方法,而這個問題在ultraedit下是完全不存在的,於是從官網下載了一個繁體版,安裝之後,發現菜單欄的字符 很奇怪,但是沒反應過來其實就是亂碼,於是卸載又安裝英文版,結果菜單欄還是亂碼,於是Google解決方案,大概是因為我的電腦是中文版的,與 ultraedit的字符不兼容,而之前安裝過繁體版的ultraedit,雖然卸載,但是配置文件並沒有刪除,於是在C盤的用戶名目錄下的還存在。
    解決方案,刪除配置文件即可,在Windows 7下是C:\Users\用戶名\AppData\Roaming,話說Windows 7為了兼容大部分的xp程序,於是就有Roaming這個文件,而系統盤目錄下的Document and Setting其實是無法訪問的,我想直接就是映射到Roaming這個目錄裡吧。

以上文字引自該網站http://ordinarysky.cn/?tag=菜單欄亂碼


—————————————————————————————————————————————————

    今天在網上搜了一天  儘是些說UltraEdit顯示中文什麼的出現亂碼的,天知道我會碰到菜單欄亂碼的問題,好不容易找到一個是在Win7環境下的。不過以上方法說的我個人感覺有點不準確。

    我還參考了另外一種方法,之前在找這個問題的時候,發現XP環境下說的是刪除一個IDMComp文件夾就行了,不是IDMComputer文件夾,我記得我找到過一個叫這個的文件夾,結果還含有系統文件刪不掉。

    後來我發現,IDMComp就在Roaming目錄下C:\Users\Administrator\AppData\Roaming\IDMComp
或者C:\Documents and Settings\Administrator\AppData\Roaming\IDMComp兩種方法一樣的。

    就是刪除掉Roaming下的IDNComp文件夾,然後點回收站清空,搞定。重新打開你的UltraEdit,絕對OK!

[轉] linux中select()函數分析

Select在Socket編程中還是比較重要的,可是對於初學Socket的人來說都不太愛用Select寫程序,他們只是習慣寫諸如connect、accept、recv或recvfrom這樣的阻塞程序(所謂阻塞方式block,顧名思義,就是進程或是線程執行到這些函數時必須等待某個事件的發生,如果事件沒有發生,進程或線程就被阻塞,函數不能立即返回)。可是使用Select就可以完成非阻塞(所謂非阻塞方式non-block,就是進程或線程執行此函數時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函數的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回一個代碼來告知事件未發生,而進程或線程繼續執行,所以效率較高)方式工作的程序,它能夠監視我們需要監視的文件描述符的變化情況——讀寫或是異常。下面詳細介紹一下!

Select的函數格式(我所說的是Unix系統下的伯克利socket編程,和windows下的有區別,一會兒說明):

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

先說明兩個結構體:

第一,struct fd_set可以理解為一個集合,這個集合中存放的是文件描述符(file descriptor),即文件句柄,這可以是我們所說的普通意義的文件,當然Unix下任何設備、管道、FIFO等都是文件形式,全部包括在內,所以毫無疑問一個socket就是一個文件,socket句柄就是一個文件描述符。fd_set集合可以通過一些宏由人為來操作,比如清空集合FD_ZERO(fd_set *),將一個給定的文件描述符加入集合之中FD_SET(int ,fd_set *),將一個給定的文件描述符從集合中刪除FD_CLR(int ,fd_set*),檢查集合中指定的文件描述符是否可以讀寫FD_ISSET(int ,fd_set* )。一會兒舉例說明。

第二,struct timeval是一個大家常用的結構,用來代表時間值,有兩個成員,一個是秒數,另一個是毫秒數。

具體解釋select的參數:

int maxfdp是一個整數值,是指集合中所有文件描述符的範圍,即所有文件描述符的最大值加1,不能錯!在Windows中這個參數的值無所謂,可以設置不正確。

fd_set *readfds是指向fd_set結構的指針,這個集合中應該包括文件描述符,我們是要監視這些文件描述符的讀變化的,即我們關心是否可以從這些文件中讀取數據了,如果這個集合中有一個文件可讀,select就會返回一個大於0的值,表示有文件可讀,如果沒有可讀的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入NULL值,表示不關心任何文件的讀變化。

fd_set *writefds是指向fd_set結構的指針,這個集合中應該包括文件描述符,我們是要監視這些文件描述符的寫變化的,即我們關心是否可以向這些文件中寫入數據了,如果這個集合中有一個文件可寫,select就會返回一個大於0的值,表示有文件可寫,如果沒有可寫的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入NULL值,表示不關心任何文件的寫變化。

fd_set *errorfds同上面兩個參數的意圖,用來監視文件錯誤異常。

struct timeval* timeout是select的超時時間,這個參數至關重要,它可以使select處於三種狀態,第一,若將NULL以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視文件描述符集合中某個文件描述符發生變化為止;第二,若將時間值設為0秒0毫秒,就變成一個純粹的非阻塞函數,不管文件描述符是否有變化,都立刻返回繼續執行,文件無變化返回0,有變化返回一個正值;第三,timeout的值大於0,這就是等待的超時時間,即select在timeout時間內阻塞,超時時間之內有事件到來就返回了,否則在超時後不管怎樣一定返回,返回值同上述。

返回值:

負值:select錯誤 正值:某些文件可讀寫或出錯 0:等待超時,沒有可讀寫或錯誤的文件

在有了select後可以寫出像樣的網絡程序來!舉個簡單的例子,就是從網絡上接受數據寫入一個文件中。

例子:

main()

{

int sock;

FILE *fp;

struct fd_set fds;

struct timeval timeout={3,0}; //select等待3秒,3秒輪詢,要非阻塞就置0

char buffer[256]={0}; //256字節的接收緩衝區

/* 假定已經建立UDP連接,具體過程不寫,簡單,當然TCP也同理,主機ip和port都已經給定,要寫的文件已經打開

sock=socket(...);

bind(...);

fp=fopen(...); */

while(1)

{

FD_ZERO(&fds); //每次循環都要清空集合,否則不能檢測描述符變化

FD_SET(sock,&fds); //添加描述符

FD_SET(fp,&fds); //同上

maxfdp=sock>fp?sock+1:fp+1; //描述符最大值加1

switch(select(maxfdp,&fds,&fds,NULL,&timeout)) //select使用

{

case -1: exit(-1);break; //select錯誤,退出程序

case 0:break; //再次輪詢

default:

if(FD_ISSET(sock,&fds)) //測試sock是否可讀,即是否網絡上有數據

{

recvfrom(sock,buffer,256,.....);//接受網絡數據

if(FD_ISSET(fp,&fds)) //測試文件是否可寫

fwrite(fp,buffer...);//寫入文件

buffer清空;

}// end if break;

}// end switch

}//end while

}//end main
參考資料:http://cuijinbird.blogchina.com/cuijinbird/1921117.html 
Part 2:
select()的機制中提供一fd_set的數據結構,實際上是一long類型的數組,
每一個數組元素都能與一打開的文件句柄(不管是Socket句柄,還是其他
文件或命名管道或設備句柄)建立聯繫,建立聯繫的工作由程序員完成,
當調用select()時,由內核根據IO狀態修改fd_set的內容,由此來通知執
行了select()的進程哪一Socket或文件可讀,下面具體解釋:

#include <sys/types.h>
#include <sys/times.h>
#include <sys/select.h>

int select(nfds, readfds, writefds, exceptfds, timeout)
int nfds;
fd_set *readfds, *writefds, *exceptfds;
struct timeval *timeout;

ndfs:select監視的文件句柄數,視進程中打開的文件數而定,一般設為呢要監視各文件
中的最大文件號加一。
readfds:select監視的可讀文件句柄集合。
writefds: select監視的可寫文件句柄集合。
exceptfds:select監視的異常文件句柄集合。
timeout:本次select()的超時結束時間。(見/usr/sys/select.h,
可精確至百萬分之一秒!)

當readfds或writefds中映像的文件可讀或可寫或超時,本次select()
就結束返回。程序員利用一組系統提供的宏在select()結束時便可判
斷哪一文件可讀或可寫。對Socket編程特別有用的就是readfds。
幾隻相關的宏解釋如下:

FD_ZERO(fd_set *fdset):清空fdset與所有文件句柄的聯繫。
FD_SET(int fd, fd_set *fdset):建立文件句柄fd與fdset的聯繫。
FD_CLR(int fd, fd_set *fdset):清除文件句柄fd與fdset的聯繫。
FD_ISSET(int fd, fdset *fdset):檢查fdset聯繫的文件句柄fd是否
可讀寫,>0表示可讀寫。
(關於fd_set及相關宏的定義見/usr/include/sys/types.h)

這樣,你的socket只需在有東東讀的時候才讀入,大致如下:

...
int sockfd;
fd_set fdR;
struct timeval timeout = ..;
...
for(;;) {
FD_ZERO(&fdR);
FD_SET(sockfd, &fdR);
switch (select(sockfd + 1, &fdR, NULL, &timeout)) {
case -1:
error handled by u;
case 0:
timeout hanled by u;
default:
if (FD_ISSET(sockfd)) {
now u read or recv something;
/* if sockfd is father and
server socket, u can now
accept() */
}
}
}

所以一個FD_ISSET(sockfd)就相當通知了sockfd可讀。
至於struct timeval在此的功能,請man select。不同的timeval設置
使使select()表現出超時結束、無超時阻塞和輪詢三種特性。由於
timeval可精確至百萬分之一秒,所以Windows的SetTimer()根本不算
什麼。你可以用select()做一個超級時鐘。

FD_ACCEPT的實現?依然如上,因為客戶方socket請求連接時,會發送
連接請求報文,此時select()當然會結束,FD_ISSET(sockfd)當然大
於零,因為有報文可讀嘛!至於這方面的應用,主要在於服務方的父
Socket,你若不喜歡主動accept(),可改為如上機制來accept()。

至於FD_CLOSE的實現及處理,頗費了一堆cpu處理時間,未完待續。

--
討論關於利用select()檢測對方Socket關閉的問題:

仍然是本地Socket有東東可讀,因為對方Socket關閉時,會發一個關閉連接
通知報文,會馬上被select()檢測到的。關於TCP的連接(三次握手)和關
閉(二次握手)機制,敬請參考有關TCP/IP的書籍。

不知是什麼原因,UNIX好像沒有提供通知進程關於Socket或Pipe對方關閉的
信號,也可能是cpu所知有限。總之,當對方關閉,一執行recv()或read(),
馬上回返回-1,此時全局變量errno的值是115,相應的sys_errlist[errno]
為"Connect refused"(請參考/usr/include/sys/errno.h)。所以,在上
篇的for(;;)...select()程序塊中,當有東西可讀時,一定要檢查recv()或
read()的返回值,返回-1時要作出關斷本地Socket的處理,否則select()會
一直認為有東西讀,其結果曾幾令cpu傷心欲斷針腳。不信你可以試試:不檢
查recv()返回結果,且將收到的東東(實際沒收到)寫至標準輸出...
在有名管道的編程中也有類似問題出現。具體處理詳見拙作:發佈一個有用
的Socket客戶方原碼。

至於主動寫Socket時對方突然關閉的處理則可以簡單地捕捉信號SIGPIPE並作
出相應關斷本地Socket等等的處理。SIGPIPE的解釋是:寫入無讀者方的管道。
在此不作贅述,請詳man signal。

以上是cpu在作tcp/ip數據傳輸實驗積累的經驗,若有錯漏,請狂炮擊之。

唉,昨天在hacker區被一幫孫子轟得差點兒沒短路。ren cpu(奔騰的心) z80

補充關於select在異步(非阻塞)connect中的應用,剛開始搞socket編程的時候
我一直都用阻塞式的connect,非阻塞connect的問題是由於當時搞proxy scan
而提出的呵呵
通過在網上與網友們的交流及查找相關FAQ,總算知道了怎麼解決這一問題.同樣
用select可以很好地解決這一問題.大致過程是這樣的:

1.將打開的socket設為非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完
成(有的系統用FNEDLAY也可).

2.發connect調用,這時返回-1,但是errno被設為EINPROGRESS,意即connect仍舊
在進行還沒有完成.

3.將打開的socket設進被監視的可寫(注意不是可讀)文件集合用select進行監視,
如果可寫,用
getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int));
來得到error的值,如果為零,則connect成功.

在許多unix版本的proxyscan程序你都可以看到類似的過程,另外在solaris精華
區->編程技巧中有一個通用的帶超時參數的connect模塊.

2013年11月12日 星期二

C - Function Pointer


今天在研究 C Function Pointer 的部分,原本有些誤解,後來查了一些資料後,終於釐清 Function Pointer 的觀念了!

Function Pointer 顧名思義,就是指向 Function 的指標

在 C 語言中,不論是 variable、array、struct、或是 function(一段程式碼),都有所屬的啟始記憶體位置

由此可知,main function 也是有其啟始記憶體位置。

而 function pointer 的宣告跟使用 function 時所要注意的地方是相同的,有以下幾點必須注意:
  1. 回傳值型態(return type)
  2. 參數數量(augument count)
  3. 參數型態(argument type)

以下直接用一個簡單範例來說明 function pointer 的使用:
#include <stdio.h>

//function宣告 
int doAdd(int, int);
int doMinus(int, int);

int main(void) {
   //宣告 function pointer
   //注意所設定的參數數量與型態
   int (*my_func_ptr)(int, int);

   //function pointer 指向 doAdd
   my_func_ptr = doAdd;
   printf("function pointer 指向 doAdd => %d\n", (*my_func_ptr)(5, 3));    //結果:8

   //function pointer 指向 doMinus
   my_func_ptr = doMinus;
   printf("function pointer 指向 doMinus => %d\n", (*my_func_ptr)(5, 3));  //結果:2 

   return 0;
}   //end main


int doAdd(int a, int b) {
   return a + b;
}   //end doAdd

int doMinus(int a, int b) {
   return a - b;
}   //end doMinus
從上面的範例可以看出,doAdd() 與 doMinus() 兩個 function 的回傳值型態、參數數量、參數型態都是相同的,只是名稱不同而已。

而名稱不同,卻不影響 function pointer 的使用,因為我們所用的是 function 的啟始記憶體位置

而 function pointer 的使用,有一點相當重要,即是 function pointer 的宣告;而 function pointer 的宣告,即是要注意到「回傳值型態」、「參數數量」、「參數型態」這三個部分。

當 function pointer 的宣告完成後,另外一個需要注意的就是每個 function 的啟始記憶體位置;而每個function 的啟始記憶體位置,即為 function 的名稱

在程式中,就是透過將 function pointer 指向不同 function 的啟始記憶體位置,來執行不同的 function。

2013年11月6日 星期三

第10章 ARM與DSP的架構與流程

http://www.docin.com/p-49044186.html

bss,data,text,rodata,heap,stack,常量段

bss段:
BSS段(bsssegment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域BSS是英文BlockStarted by Symbol的簡稱。BSS段屬於靜態內存分配。
data段:
數據段(datasegment)通常是指用來存放程序中已初始化的全局變量的一塊內存區域。數據段屬於靜態內存分配。
text段:
代碼段(codesegment/textsegment)通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域通常屬於只讀,某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量等。
rodata
存放C中的字符串和#define定義的常量
heap堆:
堆是用於存放進程運行中被動態分配的內存段,它的大小並不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)
stack棧:
是用戶存放程序臨時創建的局部變量,也就是說我們函數括弧「{}」中定義的變量(但不包括static聲明的變量,static意味著在數據段中存放變量)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的返回值也會被存放回棧中。由於棧的先進先出特點,所以棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。

常量段:
常量段一般包含編譯器產生的數據(與只讀段包含用戶定義的只讀數據不同)。比如說由一個語句a=2+3編譯器把2+3編譯期就算出5,存成常量5在常量段中

一般情況下,一個程序本質上都是由 bss段、data段、text段三個組成的——本概念是當前的計算機程序設計中是很重要的一個基本概念。而且在嵌入式系統的設計中也非常重要,牽涉到嵌入式系統運行時的內存大小分配,存儲單元佔用空間大小的問題。
在採用段式內存管理的架構中(比如intel的80x86系統),bss段(Block Started by Symbol segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域,一般在初始化時bss 段部分將會清零(bss段屬於靜態內存分配,即程序一開始就將其清零了)。
比如,在C語言程序編譯完成之後,已初始化的全局變量保存在.data 段中,未初始化的全局變量保存在.bss 段中。   
l          text和data段都在可執行文件中(在嵌入式系統裡一般是固化在鏡像文件中),由系統從可執行文件中加載;
l          而bss段不在可執行文件中,由系統初始化

編譯兩個小程序如下:
程序1:
int ar[30000];
void main()
{
    ......
}

程序2:
int ar[300000] =  {1, 2, 3, 4, 5, 6 };
void main()
{
    ......
}
    發現程序2編譯之後所得的.exe文件比程序1的要大得多。 為什麼?
區別很明顯,一個位於.bss段,而另一個位於.data段,兩者的區別在於
l          全局的未初始化變量存在於.bss段中,具體體現為一個佔位符;全局的已初始化變量存於.data段中;
l          而函數內的自動變量都在棧上分配空間。
l          .bss是不佔用.exe文件空間的,其內容由操作系統初始化(清零);
l          而.data卻需要佔用,其內容由程序初始化,因此造成了上述情況。

注意:
l          bss段(未手動初始化的數據)並不給該段的數據分配空間,只是記錄數據所需空間的大小。
l          data(已手動初始化的數據)段則為數據分配空間,數據保存在目標文件中。
l          DATA段包含經過初始化的全局變量以及它們的值。
l          BSS段的大小從可執行文件中得到,然後鏈接器得到這個大小的內存塊,緊跟在數據段後面。當這個內存區進入程序的地址空間後全部清零。包含DATA和BSS段的整個區段此時通常稱為數據區。

Program / Process / Thread 的差別

Program:放在二次儲存裝置中,尚沒有被Load到記憶體的一堆Code
         稱之為「程式」。  (也就是還是死的)


Process:已經被Load到記憶體中,任何一行Code隨時會被CPU執行,且其宣告的在記憶體
         的變數的值會隨著需求而不斷變動。
         稱之為「程序」。 (也就是活的Program) => 恐龍本第三章
         一個多工作業系統(Multitasking Operating System)可以同時運行多個Process
         然而一個CPU一次只能做一件事情,但CPU的數量永遠少於運行中的Process數,
         因此每個Process使用的時間需要被排程(Scheduling) => 恐龍本第五章
         又每個Process間在記憶體中,如果擺放的方式不當,就會在記憶體中產生很多
         沒辦法用到的碎片,因此MemoryManagement是一個問題 => 恐龍本第八章
         另外,每個Process所需要的記憶體總合,也可能大於實體記憶體,因此需要另
         外用二次儲存裝置充當虛擬記憶體(Virtual Memory),但是二次儲存裝置的速
         度肯定很慢,因此如何做到對虛擬記憶體最小的依賴,盡量避免Page Fault(電
         腦在主記憶體中找不到資料,而要去二次記憶體找,就稱為Page Fault)
         防止Thrashing的發生(因為Virtual Memory演算法不當,造成幾乎每次存取都要
         依賴二次記憶體,就是Thrashing),以達到效能最佳化,也是個學問 => 第九章




Thread :在同一個Process底下,有許多自己的分身,就是Thread,中文又翻成執行緒。
         以往一個Process一次只能做一件事情,因此要一面輸入文字,一面計算字數,
         這種事情是不可能的。但是有了Thread之後,可以在同一個Process底下,讓輸
         入文字是一個Thread,計算文字又是另外一個Thread,對CPU來說兩個都是類似
         一個Process,因此兩個可以同時做。
         又一個Process底下有數個Thread,而一個Process的Global Variable可以讓
         它的所有Thread共享,也就是所有Thread都可以存取同一個Process的Global
         Variable。而每個Thread自己也有自己的專屬Variable。 => 恐龍本第四章
         但是,如果有兩個Thread要存取同一個Global Variable,有可能發生問題,
         也就是說可能會存取到錯的值(例如兩個Thread同時要對一個Variable做加減,
         最後那個答案可能會是錯的),這就是Synchronization問題 =>恐龍本第六章
         又,每一個Thread之間可能會互搶資源,而造成死結(Deadlock),只要以下四
         個條件都滿足就有死結。(1)這個資源不能同時給兩個人用 (2)有一個人拿了一
         個資源,又想拿別人的資源 (3)如果一個人占了茅坑不拉屎,占用資源很久,仍
         不能趕他走 (4)A等B,B等C,C等D,D又等A 等成一圈。 要解決這種狀況有
         Avoid(預防) 或 避免(Prevent)兩種方式,破除以上四種其中一種即可。
         => 恐龍本第七章

2013年11月5日 星期二

認識 IRQ 及資源分配問題

常見的問題 
  你要求任何一個電腦技術人員列舉所有常見的電腦問題,其中資源(PC' system resources,電腦系統資源)衝突定必是這個問題清單的頭一二位。這些令人煩惱的衝突主要是由於電腦系統資源不足而最終導致死機、間歇性系統故障及資料流失等情 況。 
  要解決這些問題,其中一個要辦法就是從IRQ 〈Interrupt Request Lines,中斷請求線)入手。當然,你要知道甚麼是 IRQ 及 IRQ 如何運作。認識以後,便能一步步地解決 IRQ 的衝突及電腦系統的問題。 

甚麼是電腦系統資源 
  電腦系統資源可被理解成為電腦系統內的一部份,但不是指物理層次上的(因為我們眼不能見,手也觸摸不到),而是概念上的。這些資源對電腦系統非常重要,必須小心地分配給系統內各驅動器使用。這些資源的主要用途有二:第一,用作驅動器之間的溝通及訊息傳送;第二,用作管理各驅動器如何存取記憶體。某些電腦資源是供不應求的, 換句話說,不斷增加電腦系統的週邊設備,只會令這些資源更顯缺乏,無法滿足所有設備的要求。這些資源主要有四種,第一當然是IRQ,其餘三個分別是直接記憶體取存通道(Direct Memory Access (DMA) Channels)、輸入輸出地址 (Input/output(I/O)Addresses)及記憶體地址 ( Memory Address)。 

多工處理 
  中央處理器是電腦系統的心臟,本是被設計成為只能在一個時間處理一個工作。但大家的經驗都是,我們可以同時要求電腦處理超過一個工作,特別是使用到一些能夠多工處理(multitasking 〉的操作系統(operating system),例如WIN95或以上等,我們確是可以一邊下載軟件、一邊聽音樂、一 邊使用文書處理器。是何道理呢?那是因為處理器 不停地快速轉換工作而造成的錯覺,或是速度之高使我們未能察覺。最終,處理器還是只能"專注地工作"。 
  對於電腦各部份不停地發出對處理器的要求又如何排遣?就好像地方各區不斷地要求中央政府工作,怎樣的安排才能平衡各界呢?這就是中斷(intcrrupt)的基本概念。 
當一個裝置要求做資料的傳輸,它就會發出一個中斷訊號給處理器,比方說:“我需要你的注意。”這時處理器就會停止手頭上的工作,處理新的要求。 

中斷的運作 
  電腦各裝置就是利用IRQ產生中斷訊號要求被處理器注意。每一個裝置會有一個或更多的IRQ。當裝置要求被注意時,它就會將中斷訊號放進IRQ,然後中斷控制器(interrupt controller,下稱控制器)會識別這些中斷訊號並將之傳送到處理器。 控制器同時會告訴處理器這些訊號的優先次序,好讓處理器再安排工作,這叫做“中斷服務”。 

IRQ分配至控制器 
  最早期的個人電腦,只有一個控制器,管理八個IRQ。後來、IBM於1984年在PC/AT的機種中加多一個控制器,為連接起兩個控制器,第二個控制器的記號將會透過IRQ2連接到第一個控制器,至於原使用IRQ2的訊號則會在主機板上“被導向”改用IRQ9,此格式一直沿用至今。所以今日電腦最多有16個lIRQ,平均分配給兩個控制器負責。即第一個控制器負責IRQ0至IRQ7,第二個控制器負責IRQ8至IRQ15。 

IRQ的優先次序 
  不同IRQ的用途與優先次序使得電腦系統內的不同裝置不重復地產生中斷訊號。各IRQ的優次由高至低分別是0、1、8、9、 10、 11、12、 13、 14、 15、3、4、5、6及7。 
  因為第二個控制器使用IRQ2傳送訊號至第一個控制器,所以它所負責的IRQ8至IRQ15的優次介乎IRQ1至IRQ3中間。 

IRQ的分享 
  傳統的中斷訊號是單一裝置所發出。因為系統總線(system bus)的設計所限,多於一個裝置同時使用同一條IRQ是不可能的。這只會令處理器混亂造成錯誤的回應。不過,多於一個裝置分享同一條IRQ在有限制的條件下卻是可能的,例如兩個裝置很少使用或同時使用,實例是電腦系統內的四個通訊連接端口(communications port,COM)共分享二個IRQ(IRQ4及IRQ3〉。但這做法只會傾向產生問題多於解決問題,不是最好的。新一代的電 腦,多個週邊元件互連(Peripheral Component Interconnect,PCI)透過PCI總線及個別元件的控制器,則能夠有效他分享IRQ避免衝突。 

IRQ的工作 
  因為IRQ的數量有限,所以IRQ的工作分配一定要清晰及準確。正常情況下,每一個IRQ都有內設或標準的用途,其中部份的IRQ是保留給電腦系統內部使用,包括IRQO、1、8及13。而大家不是善忘的話,該記得IRQ2是已不復存在的了。 

更改IRQ的設定 
  某些週邊器材會指定使用哪一條IRQ及其用途,是無法更改的。但其餘大部份的IRQ仍可按用戶需要更改選擇,避免衝突。以下就是其中五個可使用的方法: 
a. 更改硬件設定。 
某些較舊的硬件可透過設定跨接線(jumpers)及開關(switch)更改IRQ的選擇,但由於此方法並不方便、所以新的硬件已不備有這個功能。 
b. 使用配置程式。 
不少新的裝置會備有個別獨特的配置程式,用戶可以透過這些程式更改IRQ的選擇。 
c. 使用視窗的裝置管理員。 
有些裝置是可以透過視窗的裝置管理員更改資源運用。 
d. 隨插隨用。 
在備有隨插隨用特性的操作系統及特定的裝置,用戶或可在安裝時選擇IRQ的安排。 
e. 檢查系組內IRQ的使用。 
視窗95或以上的操作系統,可以簡單地檢查關於IRQ的使用分配。 用戶可循以下途徑找到: 控制台→系統→裝置管理員→內容(選取電腦的情況下)→確定是IRQ的選項。 

衝突與病徵 
  現在我們算是初步認識了IRQ,接著就是認識關於IRQ的衝突。當兩個或以上的裝置嘗試同時使用同一個資源時就會發生資源衝突。而當上述所指的資源是IRQ時,就是IRQ衝突了。有些衝突是容易被識別,但有些衝突因為故障的出現不直接甚至出現一些不似是由裝置問題造成的“症狀”,故難以被發現及更正,以下就是部份常見的“病徵”: 
1. 當使用某些裝置時“當機”; 
2. 音效卡出現雜音; 
3. 打印時輸出不正確或出現其他圖文; 
4. 滑鼠的指標拒絕移動或出現“口吃”; 
5. 視窗顯示錯誤訊息又或突然以安全模式(safe mode)運作; 
6. 應用程式衝突並沒有提供原因; 
7. 新的週邊加入以後,電腦系統出現奇怪行徑。 
  當然發生IRQ衝突時會出現以上情況,但有以上情況的又未必一定是IRQ衝突。而且“病發”與被病毒感染的情況很相似,所以當你懷疑是電腦資源衝突時,宜先檢查電腦系統內有沒有病毒。 

如何解決衝突呢 
IRQ衝突通常是意外的錯誤設定所造成。所以要解決衝突,理論上,就只是以下二個簡單的步驟: ヾ 
a. 檢視lIRQ與裝置之間的合作情況; ヾ 
b. 確定哪個是衝突的裝置及 ヾ 
c. 改變資源設定,解決衝突。 
  第一步可以按上文所示從控制台內的系統檢視。第二步就需要做一點研究的功夫。除了解IRQ的使用情況外,用戶可以到裝置管理員,有沒有裝置出現“黃圈內的感嘆號”,那些裝置就是最大的“嫌疑犯”。用戶當然可以請教朋友,哪些是常見的資源衝突。其中IRQ2、3、4、5、7、9、 12及15是比較多出現問題的。最後,當然是更改資源設定。但這不是易做而且冒險的工作,有些裝置是不容許你更改設定的,你要首先取消“使用自動的設定”一項的選擇。以下是一些解決衝突的意見,不妨參考參考: 
a. 使用一些電腦系統的診斷工具,例如Norton Diagnostics,這些軟件會提供資源運用的分析。 但這並不是代表完美的解決方法。 ヾ 
b. 如上文所述,IRQ2與IRQ9最好不要同時使用,或當作是一個IRQ看待。 ヾ 
c. 新增Modem同時而系統又擁有COM2,衝突就會出現,除非更改Modem的設定。如果只是單單由 COM2改用COM 4、問題仍未解決,必須從IRQ 著手。 
d. 音效卡與第二個並聯端口(second parallel port) 內設同是使用IRQ5,所以必先更改其中一個設定。小心別將第一個並聯端口改用IRQ5。 

2013年11月1日 星期五

C-反轉鏈結串列(單鏈)

C-反轉鏈結串列(單鏈)
因為每次都要重新推
所以乾脆PO在這邊好了
這個用的演算法是直接一個一個更改"下一個的指標(ptr->nl)"來達成
至於各個步驟詳解
等我想不開了再來製作
struct listNode
{
    data a;
    listNode *nl;  //nl:Next Link
}
listNode * Inverse(listNode *str)//鏈結串列反轉範例  str 為鏈結串列的起始端
{
    listNode *ptr=str,*tmp=NULL;  // tmp儲存"上一個的位置"
    while(ptr->nl!=NULL)
    {
        str=ptr->nl;
        ptr->nl=tmp;
        tmp=ptr;
        ptr=str;
    }
    ptr->nl=tmp;
    return str;
}