开发者
下载

Context使用示例

单线程使用默认Context

对于简单应用,使用默认Context即可满足需求。调用aclrtSetDevice接口时,Runtime会自动创建默认Context,无需显式管理。

以下示例展示单线程使用默认Context的基础流程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 初始化Runtime
aclInit(nullptr);

// 2. 指定Device,自动创建默认Context和默认Stream
int32_t deviceId = 0;
aclrtSetDevice(deviceId);

// 3. 创建显式Stream(可选,也可直接使用默认Stream传入nullptr)
aclrtStream stream;
aclrtCreateStream(&stream);

// 4. 在Stream上下发任务
aclrtMemcpyAsync(devPtr, size, hostPtr, size, ACL_MEMCPY_HOST_TO_DEVICE, stream);
myKernel<<<8, nullptr, stream>>>(devPtr, size);
aclrtMemcpyAsync(hostPtr, size, devPtr, size, ACL_MEMCPY_DEVICE_TO_HOST, stream);

// 5. 同步等待任务完成
aclrtSynchronizeStream(stream);

// 6. 销毁显式Stream
aclrtDestroyStream(stream);

// 7. 复位Device,释放默认Context和默认Stream
aclrtResetDeviceForce(deviceId);

// 8. 去初始化
aclFinalize();

多线程并行计算

多个线程使用同一Device时,推荐为每个线程创建独立Context:

// 线程函数
void* threadFunc(void* arg) {
    int32_t deviceId = *(int32_t*)arg;

    // 每个线程创建自己的Context
    aclrtContext ctx;
    aclrtCreateContext(&ctx, deviceId);

    // 创建Stream
    aclrtStream stream;
    aclrtCreateStream(&stream);

    // 执行任务
    // ... 业务逻辑 ...

    // 同步等待任务完成
    aclrtSynchronizeStream(stream);

    // 销毁资源
    aclrtDestroyStream(stream);
    aclrtDestroyContext(ctx);

    return nullptr;
}

// 主线程
int main() {
    aclInit(nullptr);

    int32_t deviceId = 0;
    aclrtSetDevice(deviceId);

    // 创建多个线程
    pthread_t threads[4];
    for (int i = 0; i < 4; i++) {
        pthread_create(&threads[i], nullptr, threadFunc, &deviceId);
    }

    // 等待线程完成
    for (int i = 0; i < 4; i++) {
        pthread_join(threads[i], nullptr);
    }

    aclrtResetDeviceForce(deviceId);
    aclFinalize();
    return 0;
}

多线程Context共享

多个线程共享同一Context时,需自行保证Stream上任务的执行顺序:

aclrtContext g_ctx;  // 全局Context

void* threadFunc(void* arg) {
    int threadId = *(int*)arg;

    // 切换到共享Context
    aclrtSetCurrentContext(g_ctx);

    // 创建线程专属Stream
    aclrtStream stream;
    aclrtCreateStream(&stream);

    // 在自己的Stream上执行任务
    // ... 业务逻辑 ...

    aclrtSynchronizeStream(stream);
    aclrtDestroyStream(stream);

    return nullptr;
}

int main() {
    aclInit(nullptr);

    int32_t deviceId = 0;
    aclrtSetDevice(deviceId);

    // 创建一个Context供多线程共享
    aclrtCreateContext(&g_ctx, deviceId);

    pthread_t threads[4];
    int threadIds[4];
    for (int i = 0; i < 4; i++) {
        threadIds[i] = i;
        pthread_create(&threads[i], nullptr, threadFunc, &threadIds[i]);
    }

    for (int i = 0; i < 4; i++) {
        pthread_join(threads[i], nullptr);
    }

    aclrtDestroyContext(g_ctx);
    aclrtResetDeviceForce(deviceId);
    aclFinalize();
    return 0;
}

Context切换

使用aclrtSetCurrentContext切换当前线程的Context:

// 在Device 0上创建两个Context
aclrtSetDevice(0);
aclrtContext ctx1, ctx2;
aclrtCreateContext(&ctx1, 0);
aclrtCreateContext(&ctx2, 0);

// 切换到ctx1
aclrtSetCurrentContext(ctx1);
aclrtStream stream1;
aclrtCreateStream(&stream1);
// ... 在ctx1上执行任务 ...

// 切换到ctx2
aclrtSetCurrentContext(ctx2);
aclrtStream stream2;
aclrtCreateStream(&stream2);
// ... 在ctx2上执行任务 ...

// 切换Context时,如果新Context属于不同Device,Device也会随之切换
aclrtSetDevice(1);
aclrtContext ctx3;
aclrtCreateContext(&ctx3, 1);

aclrtSetCurrentContext(ctx3);  // 当前Context切换为ctx3,Device也切换为1

Context参数配置

使用aclrtCtxSetSysParamOpt设置Context级别的参数:

aclrtContext ctx;
aclrtCreateContext(&ctx, 0);

// 设置Context参数(示例:设置内存配置)
aclrtCtxSetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, value);

// 获取Context参数
int64_t paramValue;
aclrtCtxGetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, &paramValue);

默认Stream获取

每个Context包含一个默认Stream,可通过接口获取:

aclrtContext ctx;
aclrtCreateContext(&ctx, 0);

// 获取当前Context的默认Stream
aclrtStream defaultStream;
aclrtCtxGetCurrentDefaultStream(&defaultStream);

// 使用默认Stream(也可直接传nullptr)
aclrtMemcpyAsync(dst, size, src, size, ACL_MEMCPY_DEVICE_TO_DEVICE, nullptr);