/* ============================================================
* sm_demo.c
* 模拟 st_sm_deinit 的三种场景
*
* 编译: gcc sm_demo.c -o sm_demo -lpthread
* 运行:
* ./sm_demo 1 worker 已经自己退出,deinit 直接收尾
* ./sm_demo 2 worker 优雅退出,deinit 等到后 join
* ./sm_demo 3 worker 退不出,deinit 超时后 detach
* ============================================================ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
/* ---------------- 可调参数 ---------------- */
#define SM_DEINIT_WAIT_MS 1000 /* deinit 最多等 1 秒 */
#define SM_DEINIT_SLICE_MS 10 /* 每 10ms 查一次 */
/* ---------------- 全局状态机 ---------------- */
typedef struct {
pthread_mutex_t lock;
pthread_t worker;
int worker_alive;
int abort_req;
int mode; /* 1/2/3,决定 worker 行为 */
} sm_t;
static sm_t g_sm;
/* ---------------- worker 线程 ---------------- */
static void *worker_thread(void *arg)
{
(void)arg;
printf("[worker] start, mode=%d\n", g_sm.mode);
pthread_mutex_lock(&g_sm.lock);
g_sm.worker_alive = 1;
pthread_mutex_unlock(&g_sm.lock);
if (g_sm.mode == 1) {
/* 场景 1:worker 干完活自己退出,不等 abort */
printf("[worker] mode 1: work 300ms then exit by itself\n");
usleep(300 * 1000);
} else if (g_sm.mode == 2) {
/* 场景 2:worker 检查 abort,收到就退 */
printf("[worker] mode 2: wait for abort\n");
while (1) {
pthread_mutex_lock(&g_sm.lock);
int stop = g_sm.abort_req;
pthread_mutex_unlock(&g_sm.lock);
if (stop) break;
usleep(10 * 1000);
}
printf("[worker] mode 2: got abort, exit\n");
} else {
/* 场景 3:worker 忽略 abort,永远不退 */
printf("[worker] mode 3: ignore abort, never exit\n");
while (1) {
usleep(10 * 1000);
}
}
pthread_mutex_lock(&g_sm.lock);
g_sm.worker_alive = 0;
pthread_mutex_unlock(&g_sm.lock);
printf("[worker] exit\n");
return NULL;
}
/* ---------------- 初始化 ---------------- */
static int sm_init(int mode)
{
memset(&g_sm, 0, sizeof(g_sm));
g_sm.mode = mode;
pthread_mutex_init(&g_sm.lock, NULL);
if (pthread_create(&g_sm.worker, NULL, worker_thread, NULL) != 0) {
perror("pthread_create");
return -1;
}
printf("[init] worker created\n");
return 0;
}
/* ============================================================
* sm_deinit ------ 完全照搬 st_sm_deinit 的结构
* ============================================================ */
static void sm_deinit(void)
{
int i = 0;
int alive = 0;
pthread_t th = 0;
/* 第 1 段:设 abort_req,读出状态 */
pthread_mutex_lock(&g_sm.lock);
g_sm.abort_req = 1;
alive = g_sm.worker_alive;
th = g_sm.worker;
pthread_mutex_unlock(&g_sm.lock);
printf("[deinit] alive=%d, th=%lu\n", alive, (unsigned long)th);
/* 第 2 段:worker 已死,直接收尾 */
if (!alive) {
if (th) {
(void)pthread_join(th, NULL);
pthread_mutex_lock(&g_sm.lock);
g_sm.worker = 0;
pthread_mutex_unlock(&g_sm.lock);
printf("[deinit] joined dead worker\n");
}
pthread_mutex_destroy(&g_sm.lock);
printf("[deinit] path 2: worker already dead, done\n");
return;
}
/* 第 3 段:轮询等待 */
printf("[deinit] waiting for worker (max %d ms)...\n", SM_DEINIT_WAIT_MS);
for (i = 0; i < SM_DEINIT_WAIT_MS / SM_DEINIT_SLICE_MS; i++) {
pthread_mutex_lock(&g_sm.lock);
alive = g_sm.worker_alive;
pthread_mutex_unlock(&g_sm.lock);
if (!alive) break;
usleep(SM_DEINIT_SLICE_MS * 1000u);
}
/* 第 4 段:等到了,join + 销毁锁 */
pthread_mutex_lock(&g_sm.lock);
if (!g_sm.worker_alive && g_sm.worker) {
th = g_sm.worker;
g_sm.worker = 0;
pthread_mutex_unlock(&g_sm.lock);
(void)pthread_join(th, NULL);
pthread_mutex_destroy(&g_sm.lock);
printf("[deinit] path 4: worker exited gracefully, done\n");
return;
}
/* 第 5 段:没等到,detach 兜底 */
if (g_sm.worker) {
(void)pthread_detach(g_sm.worker);
g_sm.worker = 0;
g_sm.worker_alive = 0;
}
pthread_mutex_unlock(&g_sm.lock);
printf("[deinit] path 5: worker still busy, detached for process exit\n");
}
/* ---------------- main ---------------- */
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("usage: %s <1|2|3>\n", argv[0]);
printf(" 1: worker exits by itself before deinit\n");
printf(" 2: worker exits gracefully on abort\n");
printf(" 3: worker never exits, deinit detaches\n");
return 1;
}
int mode = atoi(argv[1]);
if (mode < 1 || mode > 3) {
printf("mode must be 1/2/3\n");
return 1;
}
printf("==== mode %d ====\n", mode);
if (sm_init(mode) != 0) return 1;
/* 不同场景,等待时间不同 */
if (mode == 1) {
/* 等 worker 自己死 */
sleep(1);
} else if (mode == 2) {
/* 等 worker 起来 */
sleep(1);
} else {
/* 等 worker 起来 */
sleep(1);
}
printf("[main] call sm_deinit\n");
sm_deinit();
printf("[main] done\n");
return 0;
}
代码里面的知识点:

一张图总结"为什么"
进程要退出,worker 可能还在跑
│
▼
不能直接杀(丢数据、坏状态)
│
▼
优雅退出:通知 + 等待 + 收尾
│
├─ 通知 → abort_req
├─ 知状态 → worker_alive(加锁保护)
├─ 等待 → 轮询 + 超时
├─ 等到了 → join + 销毁锁
└─ 等不到 → detach 兜底,不销毁锁