I gave it up and using Firefox 3, new interface of Thread Manager, it
works quite good.
This is a discussion on thread stuck problem - Mozilla ; Hello, I am using thread in components to read and parse big file line by line, and send message to GUI about the progress. the implementation is very similar to the example from: http://skrul.com/blog/projects/threaddemo /***** * async thread for compiling ...
Hello,
I am using thread in components to read and parse big file line by
line, and send message to GUI about the progress.
the implementation is very similar to the example from:
http://skrul.com/blog/projects/threaddemo
/*****
* async thread for compiling mb. provide interface to start, pause,
resume, stop the compiling,
* using calback function to report the compiling progress.
*
*/
const CLASS_ID = Components.ID("{d41911c1-41bd-4d7d-
a1fa-1593febb0c4e}");
const CLASS_NAME = "OAKIME_MB_COMPILE_THREAD";
// textual unique identifier
const CONTRACT_ID = "@ime.oak.com/mbcompiler;1";
/*****
* load other js files
*/
var JS_FILES = [
"chrome://oakime/content/util/oakutil.js",
"chrome://oakime/content/util/OakString.js",
"chrome://oakime/content/mb/mbconst.js",
"chrome://oakime/content/mb/mbfile.js",
"chrome://oakime/content/mb/mbdef.js",
];
/************************************************** *********
class definition
************************************************** *********/
function _D (msg){
var OakIMEconsole = Components.classes["@mozilla.org/consoleservice;
1"].getService(Components.interfaces.nsIConsoleServic e);
OakIMEconsole.logStringMessage('OAK-DUMP:' +"["+msg+"]\n");
}
function loadJS(url)
{
_D('loadJS:'+url);
//get script loader
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;
1"].
getService(Components.interfaces.mozIJSSubScriptLo ader);
//load the script
try {
loader.loadSubScript(url, null);
}catch (e){
_D('load js failed:'+e);
}
}
for (var js in JS_FILES){
//_D('js.value='+js.value);
loadJS(JS_FILES[js]);
}
function TextMBCompileThread (){
}
TextMBCompileThread.prototype = {
// mbManager : null,
mbFile : null,
mb : null,
thread : null,
proxy : null,
eq : null,
eqs : null,
pom : null,
callback : null,
_cancelCompiling : false,
// nsISupports
QueryInterface : function(aIID) {
if(!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIRunnable) &&
!aIID.equals(Components.interfaces.nsIOakImeCompil eThread) &&
!aIID.equals(Components.interfaces.nsIClassInfo)){
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
},
// nsIClassInfo
getInterfaces : function(count) {
var ifaces = [
Components.interfaces.nsISupports,
Components.interfaces.nsIRunnable,
Components.interfaces.nsIOakImeCompileThread,
Components.interfaces.nsIClassInfo
];
count.value = ifaces.length;
return ifaces;
},
getHelperForLanguage : function(language) {
return null;
},
contractID : CONTRACT_ID,
classDescription : CLASS_NAME,
classID : CLASS_ID,
implementationLanguage :
Components.interfaces.nsIProgrammingLanguage.JAVAS CRIPT,
flags : Components.interfaces.nsIClassInfo.THREADSAFE,
// nsIRunnable
run : function(){
// Create an event queue for the asynch service
this.eq = this.eqs.createFromIThread(this.thread, false);
this.callback.updateInfo("thread started");
// Start the event loop.
//this.eq.eventLoop();
this._cancelCompiling = false;
var mb = new OakIMEMB ();
mb.init ();
var date0 = new Date();
var ret = mb.compileMBbyTextFile(this.mbFile, this);
var date1 = new Date();
var date2 = date1.getTime() -date0.getTime();
_D('time used:'+date2);
this.callback.compileFinished(this.mbFile);
if (ret){
this.callback.addMB(mb);
}
// Clean up when the event loop exits
this.eq.processPendingEvents();
this.eq.stopAcceptingEvents();
this.eq.processPendingEvents();
this.eqs.destroyThreadEventQueue();
this.callback.updateInfo("thread stopped");
this.proxy = null;
},
start : function(filepath, callback){
// _D('thread start: callback='+callback+'|filepath'+filepath);
this.mbFile = filepath;
this.pom = Components.classes["@mozilla.org/xpcomproxy;1"]
.getService(Components.interfaces.nsIProxyObjectMa nager);
this.eqs = Components.classes["@mozilla.org/event-queue-service;
1"]
.getService(Components.interfaces.nsIEventQueueSer vice);
// Wrap the supplied callback in a proxy using UI's event queue
this.callback =
this.pom.getProxyForObject(this.eqs.getSpecialEven tQueue(Components.interfaces.UI_THREAD_EVENT_QUEUE ),
Components.interfaces.nsIOakImeCompileCallback,
callback,
Components.interfaces.nsIProxyObjectManager.INVOKE _ASYNC);
// Create and start a thread for the asynch service
this.thread = Components.classes["@mozilla.org/thread;1"]
.createInstance(Components.interfaces.nsIThread);
this.thread.init(this,
1024*1024,
Components.interfaces.nsIThread.PRIORITY_LOW, //
PRIORITY_NORMAL,
Components.interfaces.nsIThread.SCOPE_GLOBAL,
Components.interfaces.nsIThread.STATE_UNJOINABLE);//STATE_JOINABLE);//
// this.thread.join();
/*
* HACK: We must wait for the event queue to be created on the
worker thread
* before creating the proxy.
*/
var mainThread = Components.classes["@mozilla.org/thread;1"]
.createInstance(Components.interfaces.nsIThread).c urrentThread;
var i = 0;
while(!this.eq && i < 10) {
mainThread.sleep(10);
}
if(!this.eq) {
throw Error("Event queue not found");
}
// Create a proxied version of this object for the UI to use
this.proxy =
this.pom.getProxyForObject(this.eq,
Components.interfaces.nsIOakImeCompileThread,
this,
Components.interfaces.nsIProxyObjectManager.INVOKE _ASYNC);
return this.proxy;
},
stop : function(){
// _D('cancelCompiling: called');
this._cancelCompiling = true;
//this.thread.interrupt();
//this.thread.interrupt();
},
};
/************************************************** *********
class factory
************************************************** *********/
//var oakimeCompiler = new TextMBCompileThread();
var OakimeCompilerFactory = {
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new TextMBCompileThread()).QueryInterface(aIID);
}
};
/************************************************** *********
module definition (xpcom registration)
************************************************** *********/
var OakIMECompilerModule = {
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentR egistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentR egistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
},
getClassObject: function(aCompMgr, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(CLASS_ID))
return OakimeCompilerFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
canUnload: function(aCompMgr) { return true; }
};
/************************************************** *********
module initialization
When the application registers the component, this function
is called.
************************************************** *********/
function NSGetModule(aCompMgr, aFileSpec) { return
OakIMECompilerModule; }
====================================
instead of using the message loop, //this.eq.eventLoop();
I am using thread.eq.pendingEvents () and
thread.eq.processPendingEvents(); to check the interruption event
inside the thread, while reading each of line.
isCancelCompiling : function (){
var ret = false;
if (this._thread){
if (this._thread.eq){
if (this._thread.eq.pendingEvents ()){
this._thread.eq.processPendingEvents();
}
}
ret = this._thread._cancelCompiling;
}else{
ret = this._cancelCompiling;
}
return ret;
},
the callback to update GUI.
notifyCompileInfo : function (info){
if (this._callback){
this._callback.updateInfo(info);
}
var thread = Components.classes["@mozilla.org/thread;1"]
.createInstance(Components.interfaces.nsIThread).c urrentThread;
thread.sleep(100);
},
======================================
GUI part:
try {
this._compiler = Components.classes['@ime.oak.com/mbcompiler;
1'].createInstance(Components.interfaces.nsIOakImeCom pileThread);
this._proxy = this._compiler.start(path, this);
// DUMP('_proxy='+this._proxy);
}catch (e){
DUMP(e);
}
=======================================
It can work for a while, my problem is, sometime the thread seems to
stop after parse 2-3 lines, sometime it stops after reading 1000
lines. it also stop to response to the callback event.
the Firefox can still work fine, and I can still start another
instance of the thread.
there is no any exception or error messages, how can I debug into it,
and check the status of the thread.
the FF version is 2.0.0.14, Mozilla/5.0 (Windows; U; Windows NT 5.1;
en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14
And I can not find official documents about the thread.init()
interface. because I am doubting memory/stack size and some resource
are locked by other thread.
any one can give me some hints? thanks.
I gave it up and using Firefox 3, new interface of Thread Manager, it
works quite good.