> For the complete documentation index, see [llms.txt](https://docs.proudnet.com/proudnet.cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.proudnet.com/proudnet.cn/proudnet-note/notes/main_loop.md).

# 對主循環的理解

## 客戶端主環

ProudNet的客戶端以polling方式接收信息或發生事件時，RMI呼叫回饋或事件處理器回饋僅在遊戲客戶端主循環中呼叫特定函數時的線程中回饋。

主要是因爲遊戲客戶端具有快速轉動的環路，導致意外線程活動，\
通過上述方法設計，客戶端開發者減輕了複雜線程編程的負擔。

<figure><img src="/files/UOc5YpnA97THvZZzp1qs" alt="" width="473"><figcaption><p>客戶端主環</p></figcaption></figure>

## 服務器主環

### - 接收和事件回呼

遊戲服務器利用所有CPU,在接近DB期間,爲了對其他客戶端進行接收處理,利用<mark style="color:orange;">Thread pooling</mark>,ProudNet也以這種方式啓動,因此具有以下特點。

> * 服務器啓動時，會生成一個單獨的[**Thread pool**](/proudnet.cn/proudnet-note/dictionary.md#thread-pool)。
> * 遊戲客戶端需要每隔一段時間調用函數進行接收處理，才能處理堆積的接收信息，但服務器不需要調用這種函數。
> * 服務器發生事件或RMI接收時，會在<mark style="color:orange;">Server</mark>擁有的<mark style="color:orange;">Thread pooling</mark>中回撥。
> * 對於同一客戶端的活動或RMI接收，2個以上線程中RMI接收不能同時回饋，但ProudNet必須按到達順序回饋RMI接收。 當然,針對不同客戶的事件,RMI會同時發生回撥。
> * 所有線程在回饋線程運行期間發生RMI或事件時不會立即發生回饋，但在回饋線程完成時，該回饋處於待機狀態。
> * 即使用戶實施的回撥例程運行時間較長，網絡通信也不會發生故障，因此無需自行實現單獨的線程池。

以下是在客戶端A、B、C被服務器容納的狀態下，分別表示因RMI或事件而在<mark style="color:orange;">Server</mark>內的queue等待的狀態的圖片。

> **A1,A2,A3** -> 客戶端 A 的事件或 RMI\
> **B1,B2,B3** -> 客戶端 B 的事件或 RMI\
> \
> 線程池共有2個線程。
>
> \
> 這時根據規則執行如下。
>
> * A1、A2、A3不能同時運行。
> * B1、B2、B3和C1、C2、C3同樣不是同時運行的。
> * A1、A2、A3之一和B1、B2、B3之一、C1、C2、C3之一可以同時運行。
> * 由於線程池中只有2個線程，A、B、C中的2個線程被篩選並回饋，但回饋程序首先完成線程的線程對未篩選的客戶端進行RMI或事件回饋。

<figure><img src="/files/H5X5bPCBojnEMuUFjYlW" alt=""><figcaption><p>線程池實例</p></figcaption></figure>

### - 定時回撥

就像遊戲客戶端一樣，遊戲服務器也可以每隔一段時間處理一些事情。\
在這些情況下，有一種方法具有以下簡單的環。

```
while(1)
{
    do_something(); // 執行世界轉換操作
    Sleep(1); // 等待一段時間
}
```

還有一種方法是使用 <mark style="color:orange;">Proud.CTimerThread</mark> 或 <mark style="color:orange;">Proud.CTimerQueue</mark> 在單獨線程中運行上述循環。 但是，我建議您如何直接從服務器線程池調用自定義計時器函數。

例如，當服務器只有一個線程時，如果定時器函數和活動回撥是同一線程，則可以節省critical section訪問次數。 ProudNet還內置這些功能，敬請參考。
