• 5

請問程式設計C++的include和namespace要怎麼解釋最容易了解呢?

Ricado wrote:
Java, C# 都(恕刪)


受教了,,我以為只寫韌體才比較會用到指標....
jypn ja wrote:
受教了,,我以為只寫(恕刪)


像我在寫 Mail Server 的時候,就必須用很多的指標,甚至雙重指標

POSITION GetNextPart(POSITION pos, CImapMimePart **ppMimePart);

一套 Mail Server 除了主執行緒掌控正個系統運作,最基本的就必須開啟兩個 Linstening 的通訊端(POP3/SMTP) ,更不要說對外傳遞的 SMTP 或是加上 IPV6, TLS/SSL。Linstening 作業都必須由多個 class 完成。

例如一個 SmtpListenSocket 收到連線,建立一個 SmtpThread 負責處理這個 session 的生命週期,並且由SmtpThread 實作一個SmtpSocket 負責處理 SmtpListenSocket 丟過來的通訊連線。

MailService -> SmtpListenSocket ->SmtpThread ->SmtpSocket 不使用指標怎麼傳資料?

這行則是在 SmtpSocket 中呼叫 CSmtpThread 的 PostStatusMessage 方法。
(CSmtpThread*)m_pThread)->PostStatusMessage(szError);

至於記憶體回收,一般宣告的還好,用過就刪
LPSTR lpszMessageData = ConvertLPWSTRToLPSTR(m_strAppendMessage);
outputFile.Write(lpszMessageData, strlen(lpszMessageData));
delete [] lpszMessageData;

如果是傳址的,有時候怕自己忘了,還會加註解,避免誤刪,或忘了刪。
// dynamically allocate memory for status message (receiver will delete it!)
LPTSTR lpszFileName = new TCHAR[nLength+1];
lstrcpy(lpszFileName, strFileName);
::PostMessage(AfxGetMainWnd()->m_hWnd, WM_INCOMINGMESSAGE, (WPARAM)lpszFileName, (LPARAM)NULL);


後來我用 C# 寫了一套 Web Server,這時候就不用那麼麻煩了,但是可以很明顯地看到記憶題會一直起起伏伏,也就是 .NET Framework 的 CLR 會一直等到記憶體不夠用了,才會叫用 GC 回收。
本生物已配置全天候戰鬥系統~ 手機不通、Skype 離線時,請託夢,或留言!
Ricado wrote:
像我在寫 Mail Server 的時候,就必須用很多的指標,甚至雙重指標

POSITION GetNextPart(POSITION pos, CImapMimePart **ppMimePart);

一套 Mail Server 除了主執行緒掌控正個系統運作,最基本的就必須開啟兩個 Linstening 的通訊端(POP3/SMTP) ,更不要說對外傳遞的 SMTP 或是加上 IPV6, TLS/SSL。Linstening 作業都必須由多個 class 完成。

例如一個 SmtpListenSocket 收到連線,建立一個 SmtpThread 負責處理這個 session 的生命週期,並且由SmtpThread 實作一個SmtpSocket 負責處理 SmtpListenSocket 丟過來的通訊連線。

MailService -> SmtpListenSocket ->SmtpThread ->SmtpSocket 不使用指標怎麼傳資料?

這行則是在 SmtpSocket 中呼叫 CSmtpThread 的 PostStatusMessage 方法。
(CSmtpThread*)m_pThread)->PostStatusMessage(szError);

至於記憶體回收,一般宣告的還好,用過就刪
LPSTR lpszMessageData = ConvertLPWSTRToLPSTR(m_strAppendMessage);
outputFile.Write(lpszMessageData, strlen(lpszMessageData));
delete [] lpszMessageData;

如果是傳址的,有時候怕自己忘了,還會加註解,避免誤刪,或忘了刪。
// dynamically allocate memory for status message (receiver will delete it!)
LPTSTR lpszFileName = new TCHAR[nLength+1];
lstrcpy(lpszFileName, strFileName);
::PostMessage(AfxGetMainWnd()->m_hWnd, WM_INCOMINGMESSAGE, (WPARAM)lpszFileName, (LPARAM)NULL);


後來我用 C# 寫了一套 Web Server,這時候就不用那麼麻煩了,但是可以很明顯地看到記憶題會一直起起伏伏,也就是 .NET Framework 的 CLR 會一直等到記憶體不夠用了,才會叫用 GC 回收。


交流兼請教.
有的OS好像會自己主動去作GC的動作?當程式結束時就執行GC,有的OS則是被動的,當發生Memory不夠時才執行GC?
似乎是因為service number不同(POP3/SMTP),所以必須起來兩個Listening processes分別服務?
以前在寫IPC(Inter Process Communication)的動作,可以用Share Memory或Message Queue,這些記憶體由OS自己執行GC回收.
guest2000 wrote:
有的OS好像會自己主動去作GC的動作?當程式結束時就執行GC,有的OS則是被動的,當發生Memory不夠時才執行GC?


我不是Socket專業,不過GC的時間應該跟是不是寫Socket沒有關係,所以我應該可以回答, 以前寫COM的時候,每個Class都會記錄有多少其他物件在reference自己(reference count),在寫解構式時必須保證reference count等於0才能安全下莊,在scope內new出來的物件(class),在出scope前會進入解構式,原則上來說有其他reference它的其他物件應該都是在同一個scope下且比較晚生成的(或是它的更下層),所以都會進入自己的解構式,依據巢狀結構,這些其他物件的解構式會早於被他們reference到的物件,如此而來,被他們reference到的物件的reference count就會因為他們的解構式遞減直到0,出scope時就可以安全下莊了,其實並不需要等到整個程式結束時或記憶體不夠才執行GC,所以在scope內new出一個物件傳出scope讓scope外部的物件reference是非常危險的作法,應該要避免,尤其是那種不能自己操作指標的語言,至於能自己操作指標的C++,反正delete是programmer自己寫那就風險自負了
guest2000 wrote:
交流兼請教.有的OS(恕刪)

這個不能說是被動或是主動。
一般來說 GC 的執行模式分為 workstation mode 和 server mode ,這兩者的處理頻率不同。workstation mode 簡單的說就是少量多餐,頻率比較高。server mode 則是間隔較長,雖然較耗記憶體,但是可以處理較大的資料量。

至於實作部的的 Listening 部分,在 Windows 系統,其實是同一個 Process,但是不同的通訊端,除了 port 不同,通訊協定、處理流程也不通,所以我就分別實作了不同的 class。我在 Mail Service 的程式中再 include 這些檔案進來,這是我習慣的程式結構。
#include "SmtpListenSocket.h"
#include "Pop3ListenSocket.h"
#include "ImapListenSocket.h"

#ifdef ENABLE_SSL
#include "SmtpSslListenSocket.h"
#include "Pop3SslListenSocket.h"
#include "ImapSslListenSocket.h"
#endif

每一個 ListenSocket 收到 client 的連線之後,便會新增一個相對的 Thread 去處理後續的通訊。這一部份,我又習慣拆成兩個,一個只負責週期週期、一個負責處理真正的通訊。所以,每一個通訊就會包含三個檔案,例如:
SmtpListenSocket
SmtpThread
SmtpSocket

我的不是 Inter Process Communication,而是 InProcess,只是不同執行緒。

IPC / RPC / Message Queue 處理的方式又不一樣,那是另一個課題了。基本上這些是透過記憶體複製的傳輸方式,例如您要將一個物件透過 Queue 傳遞,必須確保這個物件是可序列化的。各式各樣的通訊方式各有各的優缺點。

以被微軟自己掐死的 .NET Remoting 來說,就可以完全支援物件的傳遞。 2003 年我用這個技術實作了一個分散式物件的 framework。

目前我們公司實作的一套跨網際網路的資訊系統(Windows Form),則是使用 Google 的 gRPC 的通訊方式。
本生物已配置全天候戰鬥系統~ 手機不通、Skype 離線時,請託夢,或留言!
莎朗石頭 wrote:
我不是Socket專(恕刪)



COM 的 IUnknown Interface 包含三個方法
- QueryInterface
- AddRef
- Release

當您宣告 Dim MyObj = New MyClass (換個 VB )
這時候除了依據 MyClass 的定義在 Heap 中配置一塊記憶體,並將記憶體位址 assign (=) 給 stack 的 MyObj ,最重要的是 AddRef 會同步被呼叫,所以 counter 就會 +1

當 out of scope 或是明確的釋放 Set MyObj = Nothing
這時候 Release 就會被呼叫。 counter 就會 -1

但是,這也不是沒有缺點,如果那麼好,微軟 .NET 就不會改用 GC 了 (向 Java 致敬嗎?)。

例如有人會將物件宣告在 Global 或是 Module 的層級共用,還有更鳥的就是錯誤的上下層元件呼叫設計,造成 A 參考 B,B 參考 C,C 參考 A,那就永遠不會被釋放了。

A call B
B call C
C 要回報給 A,本來應該 RaiseEvent或是透過 delegate 一路回傳。
結果忽然發現,A 有一個方法可以直接呼叫,就直接 C call A 越級報告了
不要以為這是初學者犯的錯誤,這是我在一家高科技廠的系統看到的寫法。
本生物已配置全天候戰鬥系統~ 手機不通、Skype 離線時,請託夢,或留言!
chunchiahsieh

100分~高手!我踩過的雷你都找出來了

2022-06-29 0:03
guest2000

A call B,然後B call C,然後C call A,這種呼叫法經常會造成deadlock的出現,整個系統就hang住了(或無限等待).

2022-06-29 9:12
jeel54321 wrote:
什麼時候會用到我也很好奇?台灣有寫這種分秒必爭的程式的公司?

有,MCU上面
10年前我用ARM crotex M3跑4MHz做汽車雲端防盜器
防盜器需要省電故以最低時脈運作
Ricado wrote:
但是,這也不是沒有缺點,如果那麼好,微軟 .NET 就不會改用 GC 了 (向 Java 致敬嗎?)。


android 建議的做法是,把不想被回收的物件,宣告在不會被摧毀(destroy)的元件裡,譬如畫面建構元件。而不是相信 garbage collect,也不是使用全域靜態變數。

因為手機轉個方向或是休眠,都會摧毀原物件,再重新建構一個。
Ricado wrote:
這個不能說是被動或是主動。
一般來說 GC 的執行模式分為 workstation mode 和 server mode ,這兩者的處理頻率不同。workstation mode 簡單的說就是少量多餐,頻率比較高。server mode 則是間隔較長,雖然較耗記憶體,但是可以處理較大的資料量。


印象中C#可以透過設定的方式
使用這兩種回收方式
也可以設定heap累積多少byte後開始回收
或是在程式中直接強制回收
JAVA GC沒研究過...
chunchiahsieh wrote:
印象中C#可以透過設(恕刪)


可以利用 config 設定

<gcserver enabled="true|false"></gcserver>



其實隨著 .NET 的發展 (我算是第一代的 alpha tester),GC 的設計也不斷在改變,最早的時候很簡單,單 CPU 就是 Workstation Mode,少量多餐,不要影響程式運作。多 CPU 就是 Server Mode,獨立的行程來處理記憶體回收,因為是獨立行程,可以與應用程式並行處理。

這棟樓有幾位底子很強的大大,我們講了那麼多記憶體,對於只是強調前端、後端、全端,以及快速開發工具的程式人員,或許這些都是多餘的。有的人誤以為全端就是系統的全部,其實都是省略了一個字 WEB,web frontend, web backend, 都只是 client。

引用 https://dart.dev 首頁的一段話
Dart is a client-optimized language for fast apps on any platform

程式設計師了解指標的目的,不是只有效能問題,而是知道資料、物件的存取方式,以及生命週期的觀念。不了解指標與記憶體配置的觀念,當有一天您發現您的系統出現類似
access denied
access violation
null reference
out of memory
...

您唯一能做的可能就是重新啟動程式,甚至重開機。我看過某晶圓廠有個系統,就是專門定時重啟服務,釋放記憶體,因為系統已經病入膏肓,又不敢亂動。

十幾年前,某泛公股銀行的系統,偶爾就會當機,trace log 也可以大概知道發生在哪裡,但是因為是偶發的,所以也很難 debug,後來他們找了微軟,微軟又找我去幫忙看,我跟他們說錯在哪一段,工程師馬上說『不可能,那一段我有加 try catch...』我就跟他說,你在 catch 的部分是不是釋放一個物件?他說對。我就問他你在刪的時候有確認這個物件是否存在了嗎?

學習指標可以讓您養成好的資源處理習慣。一塊記憶體配置後,可能會有多段程序在存取,當然也包括刪除。我到現在寫程式還是會使用註解提醒自己避免犯錯,例如前面提到的

// dynamically allocate memory for status message (receiver will delete it!)

這段就是告訴自己,不可以在這裡刪。
本生物已配置全天候戰鬥系統~ 手機不通、Skype 離線時,請託夢,或留言!
  • 5
內文搜尋
X
評分
評分
複製連結
Mobile01提醒您
您目前瀏覽的是行動版網頁
是否切換到電腦版網頁呢?