David,
That behaviour sounds reasonable to me. I now realize that when I was simplifying the example we have, I went a little too far and eliminated the hierarchical aspect of the state, making the problem I ended up describing subtly different.
My understanding of loading a state is that new objects are created whether or not the same object is already loaded. That seems the right thing to do, as you say. When loading a child state however, I would expect only objects in the child state to be created and any objects not in the child to remain as they are. This does not appear to fit with our observations in relation to threads though. Loading a child state appears to prevent a running thread from picking up the latest mutable data, even though all objects used in the running thread are not in the child state. I can't recreate the issue without threads. I've updated the previous example to show this.
Sorry if I'm missing something obvious here.
Thanks, Phil
val c = ref 0;
open Thread;
fun run () : Thread.thread = let val cv = ConditionVar.conditionVar (); val m = Mutex.mutex ();
fun aux () = let open Time; val _ = ConditionVar.waitUntil (cv, m, now () + fromSeconds 1); in print (Int.toString (!c)); aux () end; in Thread.fork (aux, []) end;
PolyML.SaveState.saveState "test1.polydb"; (* save state with c = ref 0 *)
(* save a child of test1.polydb that contains nothing extra *)
PolyML.SaveState.saveChild ("test2.polydb", 1);
val t = run (); (* prints 0 on standard output every second *)
c := 2; (* now prints 2 *) c := 3; (* now prints 3 *)
(* load the child test2.polydb *)
val t = (PolyML.SaveState.loadState "test2.polydb"; t);
(* still printing 3, even though saved when c = ref 0 *)
Thread.isActive t; (* thread still active *)
c := 1; (* no effect, still prints 3... *)
!c; (* ...even though !c = 1 *)
(* kill thread and start again with same function run: now picks up current c *)
Thread.kill t;
val t = run ();
(* uses current c: now prints 1 - ok *)
c := 2; (* now prints 2 - ok *)
(* this seems strange because run is not in the child state so we would *) (* expect it to be the same object. *)
David Matthews wrote:
Phil, The idea of loadState is to be able to load information saved in a previous session and it doesn't always work as expected when you reload the state into the session that saved it. That isn't something I imagined someone wanting to do.
loadState restores the values of references in the executable to the values they had when the state was saved and this typically involves loading additional mutable and immutable data. Any existing saved state in the session is discarded but that raises the question of what happens if a thread, in particular the one actually calling loadState, is using some of the data in the old saved state. To allow this to work the contents of the old saved state is moved into the local heap before the new saved state is loaded. Most or all of it will then get garbage collected away. The effect of this is that if you happen to load the same state that has previously been loaded or saved then any objects will be duplicated. There's no check that a state is actually the same as one that was previously in the session, either loaded or saved, and in any case I'm not sure there should be.
David
Philip Clayton wrote:
David,
Thanks. This makes sense and explains why we were seeing an inactive thread. It's useful to know that values can be passed from one sessions to the next via the stack - we hadn't fully appreciated that feature.
This behaviour with threads works well for what we are trying to do but there is still something we can't explain or see how to work around: after a loadState, when the running thread retrieves a referenced value, it no longer appears to pick up the latest value. I've provided an example that demonstrates this below. Is there a way for the thread to pick up assignments to the ref variable 'c' after the loadState?
Thanks, Phil
The information contained in this E-Mail and any subsequent correspondence is private and is intended solely for the intended recipient(s). The information in this communication may be confidential and/or legally privileged. Nothing in this e-mail is intended to conclude a contract on behalf of QinetiQ or make QinetiQ subject to any other legally binding commitments, unless the e-mail contains an express statement to the contrary or incorporates a formal Purchase Order.
For those other than the recipient any disclosure, copying, distribution, or any action taken or omitted to be taken in reliance on such information is prohibited and may be unlawful.
Emails and other electronic communication with QinetiQ may be monitored and recorded for business purposes including security, audit and archival purposes. Any response to this email indicates consent to this.
Telephone calls to QinetiQ may be monitored or recorded for quality control, security and other business purposes.
QinetiQ Limited Registered in England & Wales: Company Number:3796233 Registered office: 85 Buckingham Gate, London SW1E 6PD, United Kingdom Trading address: Cody Technology Park, Cody Building, Ively Road, Farnborough, Hampshire, GU14 0LX, United Kingdom http://www.qinetiq.com/home/notices/legal.html