如何正确使用pthread_join,避免阻塞游戏玩家线程?
解决方案:避免玩家线程阻塞的单射击线程控制
问题根源
直接在玩家线程的输入循环里调用pthread_join会强制玩家线程等待射击线程完成,期间无法处理移动或其他输入,导致冻结。要实现「同一时间仅一个活跃射击线程+玩家可移动」的需求,不能用阻塞式的join,得用状态标记+线程安全检查的方式。
实现步骤
- 添加全局变量标记当前是否有活跃射击线程,并用互斥锁保护变量访问,避免多线程竞态。
- 玩家线程收到射击指令时,先检查标记:无活跃线程才创建新射击线程并设置标记。
- 射击线程执行完毕后清除标记,允许下一次射击。
修改后的代码示例
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> // 用于模拟射击延迟 pthread_t player_tid; pthread_t shot_tid; int life_points = 100; // 标记是否有活跃射击线程,加互斥锁保护 int is_shot_active = 0; pthread_mutex_t shot_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct { unsigned char x_; unsigned char y_; unsigned char type_; unsigned char index_; } parametars; void *placeShot(parametars *params) { printf("Shot fired at: %d, %d\n", params->x_, params->y_); // 模拟子弹飞行、碰撞检测的耗时 sleep(1); free(params); // 射击结束,释放活跃标记 pthread_mutex_lock(&shot_mutex); is_shot_active = 0; pthread_mutex_unlock(&shot_mutex); return NULL; } void *playerLogic() { int c; while (life_points > 0) { char shot = 0; c = getchar(); switch (c) { case ' ': shot = 1; break; case 'a': printf("Player moves left\n"); break; case 'd': printf("Player moves right\n"); break; default: break; } if (c == 'q') { life_points = 0; continue; } parametars *params; if (shot) { // 检查是否已有活跃射击线程 pthread_mutex_lock(&shot_mutex); if (!is_shot_active) { is_shot_active = 1; pthread_mutex_unlock(&shot_mutex); params = malloc(sizeof(parametars)); params->x_ = 3; params->y_ = 2; if (pthread_create(&shot_tid, NULL, (void *(*)(void *)) &placeShot, params) != 0) { printf("Failed to create shot thread\n"); // 创建失败,重置标记 pthread_mutex_lock(&shot_mutex); is_shot_active = 0; pthread_mutex_unlock(&shot_mutex); } } else { pthread_mutex_unlock(&shot_mutex); printf("Wait for current shot to finish before firing again\n"); } } } return NULL; } int main() { if (pthread_create(&player_tid, NULL, (void *(*)(void *)) &playerLogic, NULL) != 0) printf("Failed to create player thread\n"); if (pthread_join(player_tid, NULL) != 0) printf("Failed to join player thread\n"); // 销毁互斥锁 pthread_mutex_destroy(&shot_mutex); return 0; }
关键说明
- 互斥锁
shot_mutex:保护is_shot_active变量的读写,防止玩家线程和射击线程同时操作变量引发的竞态问题。 is_shot_active标记:玩家线程仅在标记为0时创建新射击线程,严格保证同一时间只有一个活跃射击线程。- 射击线程清理标记:射击完成后主动重置标记,全程不阻塞玩家线程的输入循环,玩家可正常移动。
内容的提问来源于stack exchange,提问作者Milan
相关产品推荐
相关产品推荐

