• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import taskpool from '@ohos.taskpool';
17import fs from '@ohos.file.fs';
18import { NonReentrantLock } from '../util/LockUtil';
19import logger from "../util/Logger";
20
21@Component
22export struct LockUsage {
23  taskNum: number = 10; // 任务数,实际并行线程数依设备而定
24  baseDir: string = getContext().filesDir + '/TextDir'; // 文件写入的应用沙箱路径
25  sabInLock: SharedArrayBuffer = new SharedArrayBuffer(4); // 在主线程,初始化子线程锁标志位,所使用的共享内存
26  sabForLine: SharedArrayBuffer = new SharedArrayBuffer(4); // 在主线程,初始化子线程偏移位,所使用的共享内存
27  @State result: string = "";
28  loadDialogController: CustomDialogController = new CustomDialogController({
29    builder: Dialog(),
30    alignment: DialogAlignment.Center,
31    autoCancel: false,
32    customStyle: true
33  });
34
35  build() {
36    Row() {
37      Column() {
38        // 不使用锁写入的按钮
39        Button($r('app.string.not_use_lock'))
40          .width("80%")
41          .fontSize(30)
42          .fontWeight(FontWeight.Bold)
43          .margin({ top: 30 })
44          .onClick(async () => {
45            this.startWrite(false);
46          })
47        // 使用锁写入的按钮
48        Button($r('app.string.use_lock'))
49          .width("80%")
50          .fontSize(30)
51          .fontWeight(FontWeight.Bold)
52          .margin({ top: 30 })
53          .onClick(async () => {
54            this.startWrite(true);
55          })
56        // 运行状态说明
57        Text(this.result)
58          .width("80%")
59          .fontSize(30)
60          .fontWeight(FontWeight.Bold)
61          .fontColor(Color.Blue)
62          .margin({ top: 30 })
63      }
64      .width('100%')
65    }
66    .height('100%')
67  }
68
69  startWrite(useLock: boolean): void {
70    this.loadDialogController.open();
71    // 指明运行状态为“写入文件开始”
72    this.result = getContext().resourceManager.getStringSync($r('app.string.write_file_start'));
73    // 初始化写入时的偏移量
74    let whichLineToWrite: Int32Array = new Int32Array(this.sabForLine);
75    Atomics.store(whichLineToWrite, 0, 0);
76    // 开启多线程依据偏移量指定位置写入文件
77    // 通过主线程的sabInLock:SharedArrayBuffer初始化锁,保证多线程操作同一处锁标志位
78    // 通过主线程的sabForLine:SharedArrayBuffer初始化偏移位,保证多线程操作同一处偏移位置
79    let taskPoolGroup: taskpool.TaskGroup = new taskpool.TaskGroup();
80    for (let i: number = 0; i < this.taskNum; i++) {
81      taskPoolGroup.addTask(new taskpool.Task(createWriteTask, this.baseDir, i, this.sabInLock, this.sabForLine, useLock));
82    }
83    taskpool.execute(taskPoolGroup).then(() => {
84      // 指明运行状态为“写入文件成功”
85      this.result = getContext().resourceManager.getStringSync($r('app.string.write_file_success'));
86      this.loadDialogController.close();
87    }).catch(() => {
88      // 指明运行状态为“写入文件失败”
89      this.result = getContext().resourceManager.getStringSync($r('app.string.write_file_failed'));
90      this.loadDialogController.close();
91    })
92  }
93}
94
95@Concurrent
96async function createWriteTask(baseDir: string, writeText: number, sabInLock: SharedArrayBuffer, sabForLine: SharedArrayBuffer, useLock: boolean): Promise<void> {
97  class Option { // 写入文件时的接口方法参数类
98    offset: number = 0;
99    length: number = 0;
100    encoding: string = 'utf-8';
101
102    constructor(offset: number, length: number) {
103      this.offset = offset;
104      this.length = length;
105    }
106  }
107
108  // 初始化文件目录
109  let filePath: string | undefined = baseDir + (useLock ? "/useLock.txt" : "/unusedLock.txt");
110
111  if (!fs.accessSync(baseDir)) {
112    fs.mkdirSync(baseDir);
113  }
114  // 利用主线程传入的SharedArrayBuffer初始化锁
115  let nrl: NonReentrantLock | undefined = undefined;
116  if (useLock) {
117    // 不可重入锁
118    nrl = new NonReentrantLock(sabInLock);
119  }
120
121  // 利用主线程传入的SharedArrayBuffer初始化写入文件时的偏移量
122  let whichLineToWrite: Int32Array = new Int32Array(sabForLine);
123  let str: string = writeText + '\n';
124
125  for (let i: number = 0; i < 100; i++) {
126    if (useLock && nrl !== undefined) {
127      // 获取锁
128      nrl.lock();
129    }
130    // 写入文件
131    let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
132    try {
133      fs.writeSync(file.fd, str, new Option(whichLineToWrite[0], str.length));
134    } catch (err) {
135      logger.error(`errorCode : ${err.code},errMessage : ${err.message}`);
136    }
137    fs.closeSync(file);
138    // 修改偏移量,指定下次写入时的位置
139    whichLineToWrite[0] += str.length;
140    if (useLock && nrl !== undefined) {
141      // 释放锁
142      nrl.unlock();
143    }
144  }
145}
146
147@CustomDialog
148export struct Dialog {
149  controller: CustomDialogController;
150
151  build() {
152    Column() {
153      LoadingProgress()
154        .color(Color.White)
155        .width("30%")
156        .height("30%")
157    }
158  }
159}