Problem Description
After modifying a singleton member variable within a TaskPool, the main thread continues to read the pre-modified value.
Background Knowledge
Shared module development guidelines specify that a module is loaded only once within a process. Use the
use shareddirective to mark a module as shared.Concurrency refers to the simultaneous execution of multiple tasks within the same timeframe. On multi-core devices, tasks can run in parallel across different CPUs.
Multithreaded concurrency refers to a programming model where multiple threads run simultaneously within a single program, enhancing performance and resource utilization through parallel or alternating task execution.
Troubleshooting Process
ArkTS currently provides two concurrency capabilities: TaskPool and Worker.
Both TaskPool and Worker are implemented based on the Actor concurrency model. In the Actor concurrency model, different threads do not share the same singleton object. Each thread maintains its own independent memory space. Communication between threads occurs through a message-passing mechanism, preventing direct access to each other's memory. Consequently, when a singleton object's member variable is modified within a TaskPool, the main thread reads the unmodified value. Both TaskPool and Worker multi-threading solutions are implemented based on the Actor concurrency model. Each thread possesses its own independent memory space. Modifying a singleton object in one thread does not affect the same singleton object in other threads.
Analysis Conclusion
The singleton modified in the TaskPool within the question is the singleton object for the current task thread. Singletons across different threads are independent of each other. Therefore, modifying the member variables of the singleton object within the current thread does not affect the singleton objects in other threads. If you need to achieve sharing of singleton objects across multiple threads, you can use a shared module.
Solution
Shared modules can be shared across threads, enabling operations on the same singleton object from different threads. The example code is as follows:
1.Create a singleton in the shared module.
// SharedModule.ets
import { ArkTSUtils } from '@kit.ArkTS';
import { hilog } from '@kit.PerformanceAnalysisKit';
"use shared" // Start the sharing module
@Sendable
export class TaskHandle {
private static instance: TaskHandle = new TaskHandle();
private asyncLock: ArkTSUtils.locks.AsyncLock = new ArkTSUtils.locks.AsyncLock();
private testNum: number = 0;
public async testTask(id: number) {
// Shared asynchronous threads operate on the same data
await this.asyncLock.lockAsync(async () => {
hilog.info(0x0000, 'taskpool', `TaskHandle task id: ${id} , testNum: ${this.testNum}`);
this.testNum++;
await this.sleep(1000);
hilog.info(0x0000, 'taskpool', `TaskHandle task id: ${id} , testNum: ${this.testNum}`);
})
}
public getTestNum() {
// Obtain test data
return this.testNum;
}
public sleep(time: number): Promise<void> {
// Simulated Delay Operation
return new Promise(resolve => setTimeout(resolve, time))
}
static getInstance(): TaskHandle {
// Singleton Method
return TaskHandle.instance;
}
}
2.Entry point for external calls to the singleton.
// Index.ets
import { ArkTSUtils, taskpool } from '@kit.ArkTS';
import { TaskHandle } from './SharedModule';
import { hilog } from '@kit.PerformanceAnalysisKit';
export class Test {
async testTaskpool(): Promise<void> {
// Start multiple threads to perform data operations
let task1: taskpool.Task = new taskpool.Task(func, 1);
let task2: taskpool.Task = new taskpool.Task(func, 2);
let task3: taskpool.Task = new taskpool.Task(func, 3);
await taskpool.execute(task1);
await taskpool.execute(task2);
await taskpool.execute(task3);
hilog.info(0x0000, 'taskpool', `test task api: ${TaskHandle.getInstance().getTestNum()}`);
}
}
@Concurrent
async function func(num: number): Promise<void> {
// Single asynchronous thread operation
await TaskHandle.getInstance().testTask(num);
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(()=>{
// Start thread operation
func(0)
let a = new Test()
a.testTaskpool()
})
.width('100%')
}
.height('100%')
}
}
The results are shown in the figure below:

Top comments (0)