首页 新闻 会员 周边 捐助

AS3项目,AIR开发,使用多线程Worker,怎么让多个相同的子线程判断自己是线程池中的哪一个??

0
悬赏园豆:60 [待解决问题]

AS3项目,AIR开发,使用多线程Worker,怎么让多个相同的子线程判断自己是线程池中的哪一个??

如题,假如我想使用4个相同的子线程,命名为worker1-worker4,这4个线程同时执行不同的任务。线程的创建和启动都没有问题,问题在于:如何让这4个子线程分别知道自己是哪一个线程?或者说自己在线程池中的名称/索引?不搞清这个问题,子线程就没法和主线程正确建立MessageChannel,也就没法通信。
我翻遍了所有官方的api,没找到任何有帮助的信息,也没找到相关的机制(也可能是我太菜),网上能搜到的所有方法也试过了,都失败了。
我的想法是在每个子线程内使用WorkerDomain.current.listWorkers()方法获取线程池,然后逐一判断池内某项是否等于Worker.current。看起来逻辑似乎合理,以下是我按照这个思路写的小样,运行起来虽然不报错,但也不正确。
有没有人能指出更好的思路?或者完善我的思路,Worker这玩意太难用了!

 

  1  
  2 import flash.events.Event;
  3 import flash.system.MessageChannel;
  4 import flash.system.Worker;
  5 import flash.system.WorkerDomain;
  6  
  7 var curID: int = -1
  8  
  9 var mainToWorker1: MessageChannel
 10 var mainToWorker2: MessageChannel
 11 var mainToWorker3: MessageChannel
 12 var mainToWorker4: MessageChannel
 13  
 14 var worker1ToMain: MessageChannel
 15 var worker2ToMain: MessageChannel
 16 var worker3ToMain: MessageChannel
 17 var worker4ToMain: MessageChannel
 18  
 19 if (Worker.current.isPrimordial) {
 20     var worker1 = WorkerDomain.current.createWorker(this.loaderInfo.bytes, true);
 21     var worker2 = WorkerDomain.current.createWorker(this.loaderInfo.bytes, true);
 22     var worker3 = WorkerDomain.current.createWorker(this.loaderInfo.bytes, true);
 23     var worker4 = WorkerDomain.current.createWorker(this.loaderInfo.bytes, true);
 24  
 25     mainToWorker1 = Worker.current.createMessageChannel(worker1);
 26     mainToWorker2 = Worker.current.createMessageChannel(worker2);
 27     mainToWorker3 = Worker.current.createMessageChannel(worker3);
 28     mainToWorker4 = Worker.current.createMessageChannel(worker4);
 29  
 30     worker1ToMain = worker1.createMessageChannel(Worker.current);
 31     worker2ToMain = worker2.createMessageChannel(Worker.current);
 32     worker3ToMain = worker3.createMessageChannel(Worker.current);
 33     worker4ToMain = worker4.createMessageChannel(Worker.current);
 34  
 35     worker1.setSharedProperty("mainToWorker1", mainToWorker1);
 36     worker2.setSharedProperty("mainToWorker2", mainToWorker2);
 37     worker3.setSharedProperty("mainToWorker3", mainToWorker3);
 38     worker4.setSharedProperty("mainToWorker4", mainToWorker4);
 39  
 40     worker1.setSharedProperty("worker1ToMain", worker1ToMain);
 41     worker2.setSharedProperty("worker2ToMain", worker2ToMain);
 42     worker3.setSharedProperty("worker3ToMain", worker3ToMain);
 43     worker4.setSharedProperty("worker4ToMain", worker4ToMain);
 44  
 45     worker1ToMain.addEventListener(Event.CHANNEL_MESSAGE, fstep3);
 46     worker2ToMain.addEventListener(Event.CHANNEL_MESSAGE, fstep3);
 47     worker3ToMain.addEventListener(Event.CHANNEL_MESSAGE, fstep3);
 48     worker4ToMain.addEventListener(Event.CHANNEL_MESSAGE, fstep3);
 49  
 50     worker1.start();
 51     worker2.start();
 52     worker3.start();
 53     worker4.start();
 54  
 55 } else {
 56     curID = getCurID()
 57     this["mainToWorker" + curID] = Worker.current.getSharedProperty("mainToWorker" + curID);
 58     this["worker" + curID + "ToMain"] = Worker.current.getSharedProperty("worker" + curID + "ToMain");
 59     this["mainToWorker" + curID].addEventListener(Event.CHANNEL_MESSAGE, fstep2);
 60  
 61 }
 62  
 63  
 64 function getCurID() {
 65     //这个获取ID的方式有没有问题?每个子线程中执行listWorkers()返回的结果是否一致?不知道
 66     var v = WorkerDomain.current.listWorkers()
 67     for (var a: int = 0; a < v.length; a++) {
 68         if (v[a].isPrimordial) {
 69             v.splice(a, 1)
 70             break
 71         }
 72     }
 73     for (var b: int = 0; b < v.length; b++) {
 74         if (v[b] == Worker.current) {
 75             return b + 1
 76         }
 77     }
 78 }
 79  
 80  
 81 //步骤1:点击屏幕发送初始消息
 82 stage.addEventListener("click", f1)
 83 function f1(e) {
 84     txt1.appendText("\n初始消息已发送\n")
 85     mainToWorker1.send("")
 86     mainToWorker2.send("")
 87     mainToWorker3.send("")
 88     mainToWorker4.send("")
 89 }
 90  
 91 //步骤2:子线程收到消息,发送自己的编号
 92 function fstep2(event: Event) {
 93     this["worker" + curID + "ToMain"].send(curID)
 94 }
 95  
 96 //步骤3:主线程接收子线程编号
 97 function fstep3(event: Event): void {
 98     txt1.appendText("从分支线程发来的消息是\"" + event.target.receive() + "\"\n")
 99 }
100  
孙小振的主页 孙小振 | 初学一级 | 园豆:142
提问于:2023-03-12 00:00
< >
分享
所有回答(1)
0

要让每个子线程知道自己在线程池中的位置,你可以在主线程中设置一个全局变量(例如workerIDs),并将它分配给每个子线程。你可以使用WorkerDomain.current.listWorkers()方法获得所有线程的数组,然后在循环中将每个线程的workerID属性设置为相应的索引值。

Technologyforgood | 园豆:7775 (大侠五级) | 2023-03-28 21:48

你的想法基本上是正确的,即通过 WorkerDomain.current.listWorkers() 方法获取线程池对象,然后比对当前子线程是否在线程池中,以此确定当前子线程的 ID。但是在实现时,有些问题需要注意:

WorkerDomain.current.listWorkers() 返回的数组中包含主线程和所有子线程,因此你需要先将主线程排除,否则 getCurID() 方法返回的 ID 将不是 1-4 而是 0-3。
判断子线程是否在线程池中时,不能使用 == 运算符进行比较,因为这会导致比较的始终是子线程对象的引用地址,而不是对象本身。正确的做法是使用 ObjectUtil.compare() 方法比较两个对象是否相等。
在主线程中给子线程设置属性时,属性名应该与子线程中获取属性时使用的名字相同。你现在的实现是将属性名加上了序号,而在子线程中获取属性时却没有加序号。

import flash.events.Event;
import flash.system.MessageChannel;
import flash.system.Worker;
import flash.system.WorkerDomain;
import mx.utils.ObjectUtil;

var curID:int = -1;

var mainToWorker:Vector.<MessageChannel> = new Vector.<MessageChannel>();
var workerToMain:Vector.<MessageChannel> = new Vector.<MessageChannel>();

if (Worker.current.isPrimordial) {
for (var i:int = 0; i < 4; i++) {
var worker:Worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes, true);
mainToWorker[i] = Worker.current.createMessageChannel(worker);
workerToMain[i] = worker.createMessageChannel(Worker.current);
worker.setSharedProperty("mainToWorker", mainToWorker[i]);
worker.setSharedProperty("workerToMain", workerToMain[i]);
workerToMain[i].addEventListener(Event.CHANNEL_MESSAGE, onWorkerMessage);
worker.start();
}
} else {
curID = getCurID();
mainToWorker = Worker.current.getSharedProperty("mainToWorker");
workerToMain = Worker.current.getSharedProperty("workerToMain");
mainToWorker[curID - 1].addEventListener(Event.CHANNEL_MESSAGE, onMainMessage);
}

function getCurID():int {
var workers:Array = WorkerDomain.current.listWorkers();
for (var i:int = 0; i < workers.length; i++) {
if (!workers[i].isPrimordial && ObjectUtil.compare(workers[i], Worker.current) == 0) {
return i + 1;
}
}
return -1;
}

function onWorkerMessage(event:Event):void {
var workerToMainIndex:int = workerToMain.indexOf(event.currentTarget);
trace("Worker " + workerToMainIndex + " received message from main thread");
}

function onMainMessage(event:Event):void {
var mainToWorkerIndex:int = mainToWorker.indexOf(event.currentTarget);
trace("Main thread received message from worker " + mainToWorkerIndex);
}

这个代码中,我将 mainToWorker 和 workerToMain 从一般的变量改成了 Vector.<MessageChannel>,这样可以更方便

支持(0) 反对(0) Technologyforgood | 园豆:7775 (大侠五级) | 2023-03-30 19:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册