HarmonyOS 鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题如何解决

发布于 1周前 作者 vueper 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题如何解决

【问题现象】

在TaskPool里对单例的成员变量进行了修改,主线程读取到的仍然是修改前的值。

【背景知识】

共享模块开发指导 参考文档。 并发(指南)参考文档。 多线程并发(指南)参考文档。 【定位思路】

多线程操作第一印象肯定是ArkTS异步能力TaskPool和Worker。

当前ArkTS提供了TaskPool和Worker两种并发能力,TaskPool和Worker都基于Actor并发模型实现。

在Actor并发模型中,不同线程不会使用同一个单例对象。每个线程都有自己独立的内存空间,线程之间通过消息传递机制进行通信,不会直接访问对方的内存空间,在TaskPool中对单例对象的成员变量进行修改后,主线程读取到未修改的值。

TaskPool和worker的多线程方案都是基于Actor并发模型实现的。每个线程都有自己独立的内存空间,修改一个线程的单例对象不会影响到其他线程中的同一个单例对象。

【解决方案】

共享模块可在线程间共享,可以实现在不同线程间操作同一个单例兑现,可以使用共享模块开发。

(1)在共享模块中创建单例。

// SharedModule.ets
import { ArkTSUtils } from '@kit.ArkTS';
"use shared" // 启动共享模块

@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) {
    // 共享异步线程操作同一个数据
    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() {
    // 获取测试数据
    return this.testNum;
  }

  public sleep(time: number): Promise<void> {
    // 模拟延时操作
    return new Promise(resolve => setTimeout(resolve, time))
  }

  static getInstance(): TaskHandle {
    // 单例方法
    return TaskHandle.instance;
  }
}
(2)外部调用单例的入口。

// Index.ets
import { ArkTSUtils, taskpool } from '@kit.ArkTS';
import { TaskHandle } from './SharedModule'

export class Test {
  async testTaskpool(): Promise<void> {
    // 启动多个线程执行数据操作
    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> {
  // 单个异步线程操作
  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(()=>{
          // 启动线程操作
          func(0)
          let a = new Test()
          a.testTaskpool()
        })
        .width('100%')
    }
    .height('100%')
  }
}

结果如下图所示:

结果如下图所示:

1 回复

HarmonyOS鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题,通常是由于TaskPool的线程隔离机制导致。在HarmonyOS中,TaskPool线程与主线程不共享ArkTS引擎实例,因此它们无法直接访问或修改主线程中的单例对象。

要解决这个问题,可以考虑以下方案:

  1. 使用互斥锁(Mutex):在单例模式的实现中引入互斥锁,以保护单例对象的访问和修改,确保线程安全。
  2. 原子操作:使用原子操作来检查并设置单例对象的指针,以避免多线程同时访问和修改导致的冲突。
  3. 避免在TaskPool中直接操作单例:如果可能,尽量避免在TaskPool线程中直接修改单例对象。可以通过消息传递等方式,将需要修改的数据从TaskPool线程传递回主线程,再由主线程进行单例对象的修改。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部