Usage Examples
Using the Default Context in a Single Thread
For simple applications, default contexts are sufficient. When the aclrtSetDevice API is called, Runtime automatically creates a default context, which does not need to be explicitly managed.
The following example illustrates the basic process for using the default context in a single thread:
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. Initialize Runtime. aclInit(nullptr); // 2. Specify a device. The default context and stream are automatically created. int32_t deviceId = 0; aclrtSetDevice(deviceId); // 3. Create an explicit stream (optional; you can also directly use the default stream by passing nullptr). aclrtStream stream; aclrtCreateStream(&stream); // 4. Dispatch tasks to the 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. Wait for tasks to complete. aclrtSynchronizeStream(stream); // 6. Destroy the explicit stream. aclrtDestroyStream(stream); // 7. Reset the device to release the default context and stream. aclrtResetDeviceForce(deviceId); //8. Perform deinitialization. aclFinalize(); |
Multi-threaded Parallel Computing
When multiple threads use the same device, you are advised to create an independent context for each thread.
// Thread function.
void* threadFunc(void* arg) {
int32_t deviceId = *(int32_t*)arg;
// Each thread creates its own context.
aclrtContext ctx;
aclrtCreateContext(&ctx, deviceId);
// Create a stream.
aclrtStream stream;
aclrtCreateStream(&stream);
// Execute the task.
// Call other task APIs.
// Wait for tasks to complete.
aclrtSynchronizeStream(stream);
// Destroy resources.
aclrtDestroyStream(stream);
aclrtDestroyContext(ctx);
return nullptr;
}
// Main thread.
int main() {
aclInit(nullptr);
int32_t deviceId = 0;
aclrtSetDevice(deviceId);
// Create multiple threads.
pthread_t threads[4];
for (int i = 0; i < 4; i++) {
pthread_create(&threads[i], nullptr, threadFunc, &deviceId);
}
// Wait until the threads are complete.
for (int i = 0; i < 4; i++) {
pthread_join(threads[i], nullptr);
}
aclrtResetDeviceForce(deviceId);
aclFinalize();
return 0;
}
Context Sharing Among Multiple Streams
When multiple threads share the same context, ensure the execution order of tasks on streams.
aclrtContext g_ctx; // Global context.
void* threadFunc(void* arg) {
int threadId = *(int*)arg;
// Switch to the shared context.
aclrtSetCurrentContext(g_ctx);
// Create a stream for the thread.
aclrtStream stream;
aclrtCreateStream(&stream);
// Execute the task on the created stream.
// Call other task APIs.
aclrtSynchronizeStream(stream);
aclrtDestroyStream(stream);
return nullptr;
}
int main() {
aclInit(nullptr);
int32_t deviceId = 0;
aclrtSetDevice(deviceId);
// Create a context for multiple threads to share.
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 Switching
Use aclrtSetCurrentContext to switch the context of the current thread.
// Create two contexts on device 0. aclrtSetDevice(0); aclrtContext ctx1, ctx2; aclrtCreateContext(&ctx1, 0); aclrtCreateContext(&ctx2, 0); // Switch to ctx1. aclrtSetCurrentContext(ctx1); aclrtStream stream1; aclrtCreateStream(&stream1); // ... Execute tasks on ctx1 ... // Switch to ctx2. aclrtSetCurrentContext(ctx2); aclrtStream stream2; aclrtCreateStream(&stream2); //... Execute tasks on ctx2 ... // Switching to a context on a different device switches the active device. aclrtSetDevice(1); aclrtContext ctx3; aclrtCreateContext(&ctx3, 1); aclrtSetCurrentContext(ctx3); // Switch the current context to ctx3. The device is switched to device 1.
Context Parameter Configuration
Use aclrtCtxSetSysParamOpt to set context-level parameters.
aclrtContext ctx; aclrtCreateContext(&ctx, 0); // Set context parameters (example: memory configuration). aclrtCtxSetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, value); // Get context parameters. int64_t paramValue; aclrtCtxGetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, ¶mValue);
Obtaining the Default Stream
Each context contains a default stream, which can be obtained by calling the following API:
aclrtContext ctx; aclrtCreateContext(&ctx, 0); // Get the default stream of the current context. aclrtStream defaultStream; aclrtCtxGetCurrentDefaultStream(&defaultStream); // Use the default stream (or pass nullptr directly). aclrtMemcpyAsync(dst, size, src, size, ACL_MEMCPY_DEVICE_TO_DEVICE, nullptr);
Parent topic: Context Management