# 任务系统概要

# 任务的启动

任务通过调用父任务的 AddTask 来启动，此时会进入队列中等待启动，父任务的 EventLoop 会接受到子任务，然后调用子任务的 Start 方法进行启动操作

## EventLoop 的初始化
为了节省资源，EventLoop 在没有子任务时不会创建协程，一直等到有子任务时才会创建，并且如果这个子任务也是一个空的 Job（即没有 Start、Run、Go）则仍然不会创建协程。

## EventLoop 停止
为了节省资源，当 EventLoop 中没有待执行的子任务时，需要退出协程。EventLoop 会在以下情况退出：

1. 没有待处理的任务且没有活跃的子任务，且父任务的 keepalive() 返回 false
2. EventLoop 的状态被设置为停止状态（-1）

# 任务的停止

## 主动停止某个任务

调用任务的 Stop 方法即可停止某个任务，此时该任务会由其父任务的 eventLoop 检测到 context 取消信号然后开始执行任务的 dispose 来进行销毁

## 任务的意外退出

当任务的 Run 返回错误，或者 context 被取消时，任务会退出，最终流程会同主动停止一样

## 父任务停止

当父任务停止并销毁时，会按照以下步骤处理子任务：

### 步骤

1. **设置 EventLoop 的状态为停止状态**：调用 `stop()` 方法设置 status = -1，防止继续添加子任务
2. **激活 EventLoop 处理剩余任务**：调用 `active()` 方法，即使状态为 -1 也能处理剩余的子任务
3. **停止所有子任务**：调用所有子任务的 Stop 方法
4. **等待子任务销毁完成**：等待 EventLoop 处理完所有子任务的销毁工作

### 设计要点

- EventLoop 的 `active()` 方法允许在状态为 -1 时调用，以确保剩余的子任务能被正确处理
- 使用互斥锁保护状态转换，避免竞态条件
- 先停止再处理剩余任务，确保不会添加新的子任务

## 竞态条件处理

为了确保任务系统的线程安全，我们采取了以下措施：

### 状态管理
- 使用 `sync.RWMutex` 保护 EventLoop 的状态转换
- `add()` 方法使用读锁检查状态，防止在停止后添加新任务
- `stop()` 方法使用写锁设置状态，确保原子性

### EventLoop 生命周期
- EventLoop 只有在状态从 0（ready）转换到 1（running）时才启动新的 goroutine
- 即使状态为 -1（stopped），`active()` 方法仍可被调用以处理剩余任务
- 使用 `hasPending` 标志和互斥锁跟踪待处理任务，避免频繁检查 channel 长度

### 任务添加
- 添加任务时会检查 EventLoop 状态，如果已停止则返回 `ErrDisposed`
- 使用 `pendingMux` 保护 `hasPending` 标志，避免竞态条件