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}