1. 程式人生 > >多執行緒非阻塞模式例項

多執行緒非阻塞模式例項

多執行緒非阻塞模式到現在算是告一段落吧 雖然還有一些小的bug需要修正 總結一下  準備向後面進發  實現功能: 本程式主要實現遠端計算的功能 通過非阻塞套接字和多執行緒的結合 讓通訊變得高效  伺服器通過維護一個客戶端連結串列來實現對多個客戶響應  客戶端自身驗證表示式的正確性 當輸入Byebye時 伺服器回覆OK  此時客戶端斷開連線退出      主要模組和執行緒管理      伺服器:                主執行緒:初始化伺服器                            執行伺服器
                     退出伺服器
               監聽執行緒:
                           接收客戶端連線請求                            建立客戶端節點                            啟動對客戶端節點的服務                清理執行緒:                            當伺服器執行時:                                 定期檢查清理已退出的客戶節點                            當伺服器斷開時                                   斷開所有對客戶端的連線                                  清理客戶節點知道客戶端連結串列為空
               客戶端類:接收執行緒:                                            接收客戶端的資料 並且處理                               傳送執行緒:                                            傳送已經處理後的資料        客戶端:                主執行緒:                          初始化客戶端                          連線伺服器                          執行處理輸入輸出
                         退出客戶端                接收資料執行緒:                          接收伺服器資料 並且通知主執行緒顯示                傳送資料執行緒:                          傳送主執行緒處理好的資料 關於執行緒同步: 從客戶端說起:                     各個執行緒維持一個執行狀態變數bConning 用於執行緒迴圈外側檢測退                          主執行緒在成功連線至伺服器後 bConning = TRUE 建立接收和傳送執行緒                      這三個執行緒之間的互動:                     一。正常互動                                         1.主執行緒在執行輸入處理完資料後放入SendBuf 通過hEventSendData來通知傳送執行緒(對SendBuf互斥訪問)                                         2.接收執行緒在將接收資料拷貝到RecvBuf後 通過hEventShowData來通知主執行緒顯示資料(對RecvBuf互斥訪問)                     二。退出互動                                         1.接收執行緒先退出 設定bConning為FALSE 並SetEvent(hEventShowData)                                                                    對於傳送執行緒  檢測到bConning==FALSE 立即退出                                                                    對於主執行緒     在顯示資料前檢測bConning==FALSE 直接跳出 之後呼叫WaitForMutiObjects等                                      待發送執行緒和接收執行緒均退出                                          2.傳送執行緒先退出 設定bConning為FALSE 並SetEvent(hEventShowData)  如果不呼叫這條 主執行緒有可能無限等待顯示資料                                                                     對於接收執行緒 檢測到bConning為FALSE 退出迴圈                                                                     對於主執行緒     在顯示資料前檢測bConning==FALSE 跳出 等待接收和傳送均退出                                          3.主執行緒退出         當伺服器回覆"OK" 表示使用者輸入Byebye 此時斷開連線  等待接收和傳送退出                                                                      傳送和接收執行緒均檢測到bConning為FALSE 跳出迴圈 伺服器:                    伺服器的客戶端類:                       一。正常互動:                                            1.接收執行緒接收到資料後進行處理後 將資料拷貝到資料緩衝 用hEvent通知傳送執行緒傳送(對資料緩衝互斥訪問)                                             2.傳送執行緒傳送資料 並且恢復hEvent為無訊號                       二。退出互動:這裡的傳送執行緒在退出迴圈後通過WaitForSingleObject(hThreadRecv)來設定整個客戶端的m_exit狀態                                             1.接收執行緒先退出 設定bConning為FALSE SetEvent(hEvent)                                                                         傳送執行緒在等待到hEvent時 先判斷bConning==FALSE時 退出迴圈                                             2.傳送執行緒先退出:設定bConning為FALSE  在跳出迴圈後 等待接收執行緒退出 設定m_exit=TRUE 用於清理執行緒清理節點                                                            接收執行緒檢測到bConning=FALSE 跳出迴圈 退出                     伺服器三個總維護執行緒:                     一。正常互動:   類似前面 三個執行緒維護同一個狀態變數bServerRunning                                              1.伺服器主執行緒 初始化伺服器 並且根據使用者輸入開啟和斷開伺服器                                                                     在開啟伺服器時 設定bServerRunning = TRUE建立監聽和清理執行緒                                                                     在斷開伺服器時 設定bServerRunning=FALSE 並且通過清理執行緒結束的訊號量hServerEvent退出伺服器                                                    2.伺服器監聽執行緒 不斷監聽來自客服端的連線請求 新增新的客戶端節點到客戶端連結串列  並交由清理執行緒維護                                                                                                                              3.客戶端清理執行緒 測各個節點是否退出(m_Exit==TRUE) 並且移除連結串列 清理節點記憶體 當伺服器退出時 斷開所有客戶端連線  確保所有的客戶節點均已退出(cClientList.size() == 0)                    二。退出互動:    1.伺服器主執行緒先退出:伺服器主執行緒不會先退出 在接收到斷開伺服器請求時 只是bServerRunning=FALSE                                                                                 之後監聽執行緒停止  伺服器等待清理執行緒結束事hServerEvent後 退出                                               2.監聽執行緒先退出:        設定bServerRunning為FALSE 並退出                                                                                  之後清理執行緒開始斷開所有客戶端連線 清理完成後SetEvent(hServerEvent)                                                                                  而伺服器介面仍在等待輸入是否退出伺服器 一旦使用者輸入後(即使不是退出命令) 伺服器也將立即跳出迴圈 根據hServerEvent狀態退出(bug之一)                                               3.清理執行緒不會主動退出(除非遇到記憶體引用錯誤)                     總的三個模組互動:                                              客戶端退出 那麼伺服器客戶端類的SendThread或RecvThread先後遇到錯誤退出 導致節點m_Exit==TRUE 被清理                                       伺服器退出 那麼客戶端的傳送和接收將失敗 也將導致退出                                              伺服器通過清理執行緒來同時斷開所有客戶連線                                              伺服器客戶端類通過m_Exit來告訴清理執行緒可以清理該節點                                              客戶端通過回覆內容為OK來得知使用者輸入了Byebye 並且開始退出自身 總結:      不管用何種方式通訊  相關聯的幾個執行緒總會用一個變數來控制所有的其他執行緒      對於非阻塞套接字 Recv Send Connect Accept等都需要套上一個基於共同控制變數或者永真的迴圈來實現對WSAEWOULDBLOCK的返回重試      對於通過事件訊號量來通知的兩個執行緒 例如生產者 消費者(生產者生產好了通過hEvent通知消費者) 當生產者退出時 一定要通過該訊號量來通知消費者 以免消費者阻塞於WaitForSingleObject  而消費者在等到訊號量時  也一定要檢測生產者是否已經退出(或者是說在這裡的斷開了連線)  以免傳送或接收未知的資料      對於有訊號量控制的兩個同步執行緒 要注意是否有共同訪問的資料 要時刻記得對資料進行互斥訪問