1 # Synchronous Task Development (TaskPool and Worker) 2 3 4 Synchronous tasks are executed in order among multiple threads. Synchronization primitives, such as locks, are used by these tasks for coordination between each other. 5 6 7 To implement synchronous tasks, you must consider the collaboration and synchronization between multiple threads and ensure the correctness of data and program execution. 8 9 If synchronous tasks are independent of each other, you are advised to use **TaskPool**, which focuses on single independent tasks. For example, a series of imported static methods or methods implemented in singletons are independent. If synchronous tasks are associated with each other, use **Worker**, for example, methods implemented in class objects (not singleton class objects). 10 11 12 ## Using TaskPool to Process Independent Synchronous Tasks 13 14 **TaskPool** is recommended for scheduling independent tasks. Typical independent tasks are those using static methods. If a unique handle or class object constructed using a singleton points to multiple tasks and these tasks can be used between different worker threads, you can also use **TaskPool**. 15 16 1. Define a concurrency function that internally calls the synchronous methods. 17 18 2. Create a [task](../reference/apis-arkts/js-apis-taskpool.md#task), call [execute()](../reference/apis-arkts/js-apis-taskpool.md#taskpoolexecute-1) to execute the task, and perform operations on the result returned by the task. 19 20 3. Perform concurrent operations. 21 22 Simulate a singleton class that contains synchronous calls. 23 24 25 ```ts 26 // handle.ts code 27 export default class Handle { 28 static getInstance(): void { 29 // Return a singleton object. 30 } 31 32 static syncGet(): void { 33 // Synchronous getter. 34 } 35 36 static syncSet(num: number): number { 37 // Simulate synchronization step 1. 38 console.info("taskpool: this is 1st print!"); 39 // Simulate synchronization step 2. 40 console.info("taskpool: this is 2nd print!"); 41 return num++; 42 } 43 } 44 ``` 45 46 47 Use **TaskPool** to call the related synchronous methods. 48 49 50 ```ts 51 // Index.ets code 52 import taskpool from '@ohos.taskpool'; 53 import Handle from './Handle'; // Return a static handle. 54 55 // Step 1: Define a concurrency function that internally calls the synchronous methods. 56 @Concurrent 57 function func(num: number): boolean { 58 // Call the synchronous wait implemented in a static class object. 59 Handle.syncSet(num); 60 return true; 61 } 62 63 // Step 2: Create and execute a task. 64 async function asyncGet(): Promise<void> { 65 // Create a task and pass in the function func. 66 let task: taskpool.Task = new taskpool.Task(func, 1); 67 // Execute the task. 68 let res: boolean = await taskpool.execute(task) as boolean; 69 // Print the task result. 70 console.info("taskpool: task res is: " + res); 71 } 72 73 @Entry 74 @Component 75 struct Index { 76 @State message: string = 'Hello World'; 77 78 build() { 79 Row() { 80 Column() { 81 Text(this.message) 82 .fontSize(50) 83 .fontWeight(FontWeight.Bold) 84 .onClick(() => { 85 // Step 3: Perform concurrent operations. 86 asyncGet(); 87 }) 88 } 89 .width('100%') 90 .height('100%') 91 } 92 } 93 } 94 ``` 95 96 97 ## Using Worker to Process Associated Synchronous Tasks 98 99 Use **Worker** when you want to schedule a series of synchronous tasks using the same handle or depending on the same class object. 100 101 1. Create a **Worker** object in the main thread and receive messages from the worker thread. 102 103 ```ts 104 import worker from '@ohos.worker'; 105 106 @Entry 107 @Component 108 struct Index { 109 @State message: string = 'Hello World'; 110 111 build() { 112 Row() { 113 Column() { 114 Text(this.message) 115 .fontSize(50) 116 .fontWeight(FontWeight.Bold) 117 .onClick(() => { 118 let w: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts'); 119 w.onmessage = (): void => { 120 // Receive the result of the worker thread. 121 } 122 w.onerror = (): void => { 123 // Receive error information of the worker thread. 124 } 125 // Send a Set message to the worker thread. 126 w.postMessage({'type': 0, 'data': 'data'}) 127 // Send a Get message to the worker thread. 128 w.postMessage({'type': 1}) 129 // ... 130 // Select a time to destroy the thread based on the actual situation. 131 w.terminate() 132 }) 133 } 134 .width('100%') 135 } 136 .height('100%') 137 } 138 } 139 ``` 140 141 142 2. Bind the **Worker** object in the worker thread and process the synchronous task logic. 143 144 ```ts 145 // handle.ts code 146 export default class Handle { 147 syncGet() { 148 return; 149 } 150 151 syncSet(num: number) { 152 return; 153 } 154 } 155 ``` 156 157 ```ts 158 // MyWorker.ts code 159 import worker, { ThreadWorkerGlobalScope, MessageEvents } from '@ohos.worker'; 160 import Handle from './handle' // Return a handle. 161 162 let workerPort : ThreadWorkerGlobalScope = worker.workerPort; 163 164 // Handle that cannot be transferred. All operations depend on this handle. 165 let handler: Handle = new Handle() 166 167 // onmessage() logic of the worker thread. 168 workerPort.onmessage = (e : MessageEvents): void => { 169 switch (e.data.type as number) { 170 case 0: 171 handler.syncSet(e.data.data); 172 workerPort.postMessage('success set'); 173 case 1: 174 handler.syncGet(); 175 workerPort.postMessage('success get'); 176 } 177 } 178 ``` 179