You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用pthread_join,避免阻塞游戏玩家线程?

解决方案:避免玩家线程阻塞的单射击线程控制

问题根源

直接在玩家线程的输入循环里调用pthread_join会强制玩家线程等待射击线程完成,期间无法处理移动或其他输入,导致冻结。要实现「同一时间仅一个活跃射击线程+玩家可移动」的需求,不能用阻塞式的join,得用状态标记+线程安全检查的方式。

实现步骤

  1. 添加全局变量标记当前是否有活跃射击线程,并用互斥锁保护变量访问,避免多线程竞态。
  2. 玩家线程收到射击指令时,先检查标记:无活跃线程才创建新射击线程并设置标记。
  3. 射击线程执行完毕后清除标记,允许下一次射击。

修改后的代码示例

#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:13:20