Forums : Les possiblités de la plateforme Mozilla

Aller à la discussion :  Plus récente Plus ancienne

# [Résolu] Choix pour une application avec un timer

Envoyé par : thefab

Date : 17/02/2010 11:17

Bonjour,

Dans une application XULRunner (avec possibilité d'extensions) j'ai besoin d'un timer le plus précis possible et j'aimerais savoir sur quelles bases partir:

  • L'application et les extensions doivent pouvoir être informées des différents évènements, particulièrement du timer.

Voici quelques questions que je me pose:

  • Utilisation du composant Timer (XPCOM) ou setInterval (plutôt Timer je pense)
  • Gestion des évènements avec addObserver ou addEventListener
  • Placer le timer dans un thread ou non
  • Si timer dans un thread quelles difficultés pour informer le thread principal en JS (proxy ?)

Merci d'avance pour vos pistes / remarques

Fabrice

# Re: Choix pour une application avec un timer

Envoyé par : joliclic

Date : 19/02/2010 11:51

Bonjour,

je suis justement en train d'essayer de faire un métronome en application xulrunner, et j'ai pile été confronté à cette problématique.

Mes essais basiques avec setInterval/setTimeout étaient catastrophique ;) .

Ce qui marche le mieux pour l'instant, c'est un composant (en JS), lançant dans un thread séparé un nsITimer. Ce thread dispatch un event au thread principal à intervalle régulier, lequel notifie les observateurs enregistrés dans la fenêtre principale. Et çà marche du tonnerre, c'est précis au millième de seconde, çà bronche pas, du moins dans mes essais sur mon laptop.

# Re: Choix pour une application avec un timer

Envoyé par : thefab

Date : 19/02/2010 12:24

Ce qui marche le mieux pour l'instant, c'est un composant (en JS), lançant dans un thread séparé un nsITimer.

C'est bien ce qu'il me semblait. J'ai essayé les threads en JS mais comment garder le thread actif dans la méthode run ?

Mon thread semble fonctionner car j'ai bien "Je suis le thread principal: false" qui s'affiche mais while (true) n'est pas une bonne solution car ça bouffe du CPU:

function getProxyForMainThread(obj, iface)
	{
	var ThreadManager = Components.classes["@mozilla.org/thread-manager;1"]
		.getService(Components.interfaces.nsIThreadManager);

	var ProxyObjectManager = Components.classes["@mozilla.org/xpcomproxy;1"]
		.getService(Components.interfaces.nsIProxyObjectManager);

	var flags = Components.interfaces.nsIProxyObjectManager.FORCE_PROXY_CREATION | Components.interfaces.nsIProxyObjectManager.INVOKE_SYNC;

	return ProxyObjectManager.getProxyForObject(ThreadManager.mainThread, iface, obj, flags);
	}

function performLongTask()
	{
	try
		{
		var ThreadManager = Components.classes["@mozilla.org/thread-manager;1"]
			.getService(Components.interfaces.nsIThreadManager);

		var thread = ThreadManager.newThread(0);

		var task =
			{
			prompt: null,

			run: function()
				{
				// while (true)

				var ThreadManager = Components.classes["@mozilla.org/thread-manager;1"]
					.getService(Components.interfaces.nsIThreadManager);

				this.prompt.alert(null, "Thread", "Je suis le thread principal: " + ThreadManager.isMainThread);
				}
			};

		var PromptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
			.getService(Components.interfaces.nsIPromptService);

		task.prompt = getProxyForMainThread(PromptService, Components.interfaces.nsIPromptService);

		thread.dispatch(task, Components.interfaces.nsIEventTarget.DISPATCH_NORMAL);
		}
	catch (ex)
		{
		alert(ex);
		}
	}

Je suis curieux de savoir comment tu t'y es pris pour placer le timer dans ton thread.

Fabrice

# Re: Choix pour une application avec un timer

Envoyé par : joliclic

Date : 19/02/2010 14:50

J'en suis qu'au début, au stade des essais, pour l'instant je lance dans le thread 2 timers, 1 répétitif et 1 autre pour arrêter le premier. Par la suite je suppose que je l'arrêterai par une méthode dédiée.

voilà mon code, çà correspondrait à ton objet task.run:

 run: function() {
   try {
     var stopTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     var jobTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     
     var stopEvent = {
        notify: function(timer) {jobTimer.cancel(); }
     };
     
     var period = 500;
     
     var jobEvent = {
        notify: function(timer) {
           dump((Date.now()) + "\n");
           // gMainThread => Cc["@mozilla.org/thread-manager;1"].getService().mainThread;
           gMainThread.dispatch(new MainThreadRunnable("job"), Ci.nsIEventTarget.DISPATCH_NORMAL);
        }
     };
     
     stopTimer.initWithCallback(stopEvent, period * 40, Ci.nsITimer.TYPE_ONE_SHOT);
     jobTimer.initWithCallback(jobEvent, period, Ci.nsITimer.TYPE_REPEATING_PRECISE);
   
   } catch(err) {
     Components.utils.reportError(err);
   }
 },

et MainThreadRunnable.run:

 run: function() {
   try {
     // gObserverService => Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
     // this.msg == "job" ici
     gObserverService.notifyObservers(null, this.msg, null);
   } catch(err) {
     Components.utils.reportError(err);
   }
 },

# Re: Choix pour une application avec un timer

Envoyé par : thefab

Date : 20/02/2010 13:43

J'ai essayé mais mon timer s'arrête après 7-9 secondes ???

J'explore une autre piste qui semble bien fonctionner: un simple setInterval dans un Worker, après les premiers essais j'ai une précision au 10ème de seconde.

# Re: Choix pour une application avec un timer

Envoyé par : joliclic

Date : 20/02/2010 17:50

J'ai pas ce problème personnellement, le timer tourne bien le temps que je lui demande (40 * 500ms soit 20s dans le code que j'ai posté).

J'avais aussi essayé setInterval dans un worker, j'ai des performances analogues au nsITimer dans un thread (soit des variations de 5ms parfois), mais avec un inconvénient en plus, il prend toujours du retard (les variations s'ajoutent). Le nsITimer par contre cible toujours ce que je lui ai demandé (parfois un peu avant, parfois un peu après). Et je préfère ce comportement pour un métronome. Peut être que çà a une importance pour ton projet.

# Re: Choix pour une application avec un timer

Envoyé par : thefab

Date : 21/02/2010 01:45

Hello,

Merci pour ces précisions je vais tester si j'ai aussi des variations sur une longue durée même si ça n'a pas trop d'importances pour mon projet (je me base sur les valeurs de la date en cours pour des durées allant jusqu'à 1h30).

Quel OS utilises-tu ?

Voilà le code pour une horloge toute simple:

var worker;

function start()
	{
	worker = new Worker("ClockWorker.js");

	worker.onerror = function(e)
		{
		};

	worker.onmessage = function(e)
		{
		document.getElementById("clock").value = e.data;
		};

	worker.postMessage("start");
	}

ClockWorker.js

function updateTime()
	{
	var time = new Date();

	var h = time.getHours();
	var m = time.getMinutes();
	var s = time.getSeconds();

	var t = h + ":" + m + ":" + s;

	postMessage(t);
	}

setInterval(function() { updateTime(); }, 1000);

onmessage = function(e)
	{
	updateTime();
	}

Je préfère Worker au Thread car la communication est plus simple (onmessage, pas besoin de proxy), la gestion est plus simple (possibilité de l'arrêter de l'intérieur ou de l'extérieur).

Merci

Fabrice

# Re: [Résolu] Choix pour une application avec un timer

Envoyé par : Remi22

Date : 12/03/2010 14:27

Bonjour,

Je me suis un peu inspiré de ce que vous avez fait au niveau des threads, j'ai d'ailleurs utilisé la méthode via les proxies. Je rencontre malheureusement une erreur brutale lorsque je tente de réaliser des traitements à l'intérieur de mon thread. En effet, j'aimerais faire appel à des classes Java via Liveconnect. Pour cela, je charge mes jar de cette façon (instructions exécutées dans le thread) :

var myJarpath = "file://pathToMyJar/myjar.jar";
var urlArray = [];
urlArray[0] = new java.net.URL(myJarpath);

A l'éxécution de cette dernière ligne, j'obtiens :

A fatal error has been detected by the Java Runtime Environment:

  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6daa3d7c, pid=4660, tid=4472

 JRE version: 6.0_18-b07
 Java VM: Java HotSpot(TM) Client VM (16.0-b13 mixed mode, sharing windows-x86 )
 Problematic frame:
 C  [npjp2.dll+0x3d7c]

 If you would like to submit a bug report, please visit:
   http://java.sun.com/webapps/bugreport/crash.jsp
 The crash happened outside the Java Virtual Machine in native code.
 See problematic frame for where to report the bug.

Avez vous déjà eu ce genre de souci? Si j'exécute ces trois instructions en dehors du thread tout se passe bien...

Il n'est plus possible de poster des messages dans ce forum.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.