How to start manage or start a new thread? (Papyrus multithr

Post » Wed Jun 20, 2012 11:58 am

Does anyone know how we can actually control the multithreading? The contents on the wiki suggests that we can't actually start or join threads together. Am I getting the wrong impression?

What I want to do is to do a set of instructions in parallel as opposed to in sequence but it appears the only way I can do that is to try doing something by messing with RegisterForUpdate()/OnUpdate() in a dirty manner. However, this approach is likely going to be error-prone since you can't actually differentiate the different OnUpdate() events, which may cause some of them to try to do the same thing (i.e. if I have 5 spells to cast, 2 threads may decide to cast the same spell instead of 1 thread per spell).

So.. any advice?
User avatar
Nick Tyler
 
Posts: 3437
Joined: Thu Aug 30, 2007 8:57 am

Post » Wed Jun 20, 2012 4:56 am

Yep, you can't mess with threads. Which is a good thing, IMO.
I mean imagine if we could, just how many people would get it wrong, consistently. Multithreading is hard, even harder to get right.
Now, add that we don't have any debugging support, no watches, nothing but Debug.Trace everything else is not as useful.

That said, it may be possible to add some support, if you add it yourself (SKSE plugin). We know the VM is multithreaded, so it should be possible, though be obviously don't know how it will behave.
User avatar
Sophie Miller
 
Posts: 3300
Joined: Sun Jun 18, 2006 12:35 am

Post » Wed Jun 20, 2012 9:40 am

Yep, you can't mess with threads. Which is a good thing, IMO.
I mean imagine if we could, just how many people would get it wrong, consistently. Multithreading is hard, even harder to get right.
Now, add that we don't have any debugging support, no watches, nothing but Debug.Trace everything else is not as useful.

That said, it may be possible to add some support, if you add it yourself (SKSE plugin). We know the VM is multithreaded, so it should be possible, though be obviously don't know how it will behave.
It's not hard to mess up a mod anyway. I've once caused savegame corruption in my mod (during a quick test for something) by not setting the contents of an array that is used by a half-done script that was not called in any way or formed. At one other time, I also tripped over a threading issue where I forgot to keep track of the RegisterForUpdate() calls. I am inclined to suspect the developers just didn't bother to make the SDK that open because they knew someone's going to do an obse pack for Skyrim sooner or later.

So there's absolutely no way around this lack of threading issue and I'd have to watch 5 Fire Atronachs spawning one by one in sequence?
User avatar
neen
 
Posts: 3517
Joined: Sun Nov 26, 2006 1:19 pm

Post » Wed Jun 20, 2012 9:46 am

A multiple spawn spell, now that's been asked several times in this forum. I'm sure someone will have come up with an acceptable solution.

If not, there are some vanilla scripts doing exactly that. I remember seeing one script that spawns three skeletons and hides their transition with portals.

Besides, what's the worst that can happen? Sure your script could stop in-between summoning some atronachs, maybe delay a sound effect, but that's about it.
User avatar
N3T4
 
Posts: 3428
Joined: Wed Aug 08, 2007 8:36 pm

Post » Wed Jun 20, 2012 5:12 am

ya I'm failing to see what the issue is here.

If you want to mitigate confusion from multiple threads use states.

What does what you're doing have to do with requiring threading?

If you're doing stuff with multiple enemies, why not just put scripts on them and have them report back to a master script on something else in the area. I have that for some encounter scripts where the spawned monsters report back to the encounter manager when they die by calling a function on the encounter manager script. I set up multiple phases by having a particular activator manage and talk to all it's component parts and talk to the master manager thing.


It's waaaaaaay simpler than it sounds. You just have to get used to calling custom functions on objects casted as your new script as a data type. Also a bit of a learning curve on getting to know the 50,000 different ways there are to get at the reference you want depending on the circumstances.

Post some specific questions about it and we'll see if we can get it rolling. Do consider states though if it's *really* a matter of having to manage multiple threads. I think that's just one possible way of approaching it, and not even the best or most flexible choice
User avatar
Tina Tupou
 
Posts: 3487
Joined: Fri Mar 09, 2007 4:37 pm

Post » Wed Jun 20, 2012 4:27 am

ya I'm failing to see what the issue is here.

If you want to mitigate confusion from multiple threads use states.

Let's suppose we have an ordered list of elements and we are keeping track of which ones to spawn by keeping a global variable of counts, then the pseudo code of a thread would look like this:

call_function(Array[count++])

Are we actually guaranteed that there will not be a circumstance at which two or more instances of these would be completed at the same time? As in count 1 -> 2 - > 4? It's probably unlikely because count++ is a pretty fast operation, but it's still a question I'd like to raise..
User avatar
Nick Swan
 
Posts: 3511
Joined: Sat Dec 01, 2007 1:34 pm

Post » Wed Jun 20, 2012 3:35 pm

You should read http://www.creationkit.com/Threading_Notes_%28Papyrus%29, it's gonna answer some of your questions. It mentions that papyrus takes implicit locks and queues execution.

And to avoid possible race-conditions, you can and should use http://www.creationkit.com/States_%28Papyrus%29 like SinderionsBones mentioned. They are the closet thing to a locking mechanism we got.
Just remember that you would want to switch states as early as possible, likely on the very first line of some event or function.
User avatar
Guy Pearce
 
Posts: 3499
Joined: Sun May 20, 2007 3:08 pm

Post » Wed Jun 20, 2012 5:21 am

You should read http://www.creationkit.com/Threading_Notes_%28Papyrus%29, it's gonna answer some of your questions. It mentions that papyrus takes implicit locks and queues execution.

And to avoid possible race-conditions, you can and should use http://www.creationkit.com/States_%28Papyrus%29 like SinderionsBones mentioned. They are the closet thing to a locking mechanism we got.
Just remember that you would want to switch states as early as possible, likely on the very first line of some event or function.
I tried it out and, to be honest, this state mechanism is really like using a bread crumbs to plug a sink: i.e. It works but is quite undesirable.

What could've been achieved by a simple fork() or new Thread() is made 10 times more complicated. I wonder why they don't just use python scripts like what some of the game engines do.
User avatar
lucile davignon
 
Posts: 3375
Joined: Thu Mar 22, 2007 10:40 pm

Post » Wed Jun 20, 2012 2:21 pm

Multithreading is handled automatically, and I prefer i that way. it's far easier to debug an issue if you can be sure that you haven't forgotten that you spawned an extra thread, or accidentally spawned ten thousand threads without intending to....
User avatar
Nicholas C
 
Posts: 3489
Joined: Tue Aug 07, 2007 8:20 am

Post » Wed Jun 20, 2012 4:14 pm

States aren't a substitute for locking. In fact they aren't even close.

That said, it isn't the end of the world, you just have to roll your own. Start http://en.wikipedia.org/wiki/Peterson%27s_algorithm.
User avatar
Sheila Esmailka
 
Posts: 3404
Joined: Wed Aug 22, 2007 2:31 am

Post » Wed Jun 20, 2012 7:57 pm

Multithreading is handled automatically, and I prefer i that way. it's far easier to debug an issue if you can be sure that you haven't forgotten that you spawned an extra thread, or accidentally spawned ten thousand threads without intending to....
Uh huh... This is not really a black and white issue where one party does all the threading. And again, it's not like you can't spawn ten thousand extra threads by accident. The RegisterForUpdate() function can do just what you are referring to.

States aren't a substitute for locking. In fact they aren't even close.

That said, it isn't the end of the world, you just have to roll your own. Start http://en.wikipedia.org/wiki/Peterson%27s_algorithm.
I did say it's better than nothing and I am not above shamelessly whining after having spent 10 times the minutes I would've needed for a single task. The last time I had that sort of feeling was programming with the libpng library in C++.
User avatar
Mimi BC
 
Posts: 3282
Joined: Sat Oct 07, 2006 10:30 pm

Post » Wed Jun 20, 2012 3:45 am

Uh huh... This is not really a black and white issue where one party does all the threading. And again, it's not like you can't spawn ten thousand extra threads by accident. The RegisterForUpdate() function can do just what you are referring to.

If you don't put protections in, yeah, but at least with RegisterForUpdate() you know exactly what's happening if you detect too many multiple threads. Imagine if you were spawning extra threads in the middle of a bunch of complicated code in a function...and then you decided that it would be a bit more efficient if you made it recursive (Which pauses the previous call, but doesn't pause the spawned threads) - Each recursive call would spawn more threads, and if you forgot to check your thread counts, you could rapidly wind up with godzilla stomping all over your code.
User avatar
Harry Leon
 
Posts: 3381
Joined: Tue Jun 12, 2007 3:53 am

Post » Wed Jun 20, 2012 9:52 am

RegisterForUpdate is like a tool for producing buggy code that bloats your save game. many modders abuse it badly. Which makes me hesitate to download mods.
User avatar
Chloe Mayo
 
Posts: 3404
Joined: Wed Jun 21, 2006 11:59 pm

Post » Wed Jun 20, 2012 6:20 am

RegisterForUpdate has a purpose, but it's easy to misuse it. The CK release and with it the appearance of papyrus wasn't that long ago.
People need to adapt, and they will. Papyrus is vastly different in many regards, things that were good practices are now bad ones.

And if you worry about misused RegisterForUpdate calls, just look inside the PEX files. If that function is used, it's name will be inside that file.
User avatar
Damned_Queen
 
Posts: 3425
Joined: Fri Apr 20, 2007 5:18 pm

Post » Wed Jun 20, 2012 3:10 pm

I'm still confused how this requires such complex thinking. You put a script on the monsters, it's an object now in terms of your scripts. You have a script on some nearby marker, it's managing things. Where does the threading come in? just have the things talk back and forth by passing 'self' to whatever needs to respond...no threads will mess up on this, I've run 18 monsters at once with this method without a hint of a hickup. They were to come 3-6 at a time, that was just testing. Keep the state (not meaning 'state' meaning, variables describing behavior) on the individual monster, and it will be responsible for the condition of it's own thread as is basic OOP

I've read this thread carefully several times and the solutions and opinions discussed, while all true in a particular context, aren't very relevant to the original issue. This problem could be made irrelevant with a *very* slight shift in the method of controlling the monsters. This is an improper application of linear thinking (threading as something that must be managed manually) into what should be the simplest of object oriented application.

Like I said, nothings been really wrong so far. At least not that I can see. I just would rather see a working mod than a demoralizing cobweb of confusion.
User avatar
loste juliana
 
Posts: 3417
Joined: Sun Mar 18, 2007 7:37 pm

Post » Wed Jun 20, 2012 2:02 pm

I'm still confused how this requires such complex thinking. You put a script on the monsters, it's an object now in terms of your scripts. You have a script on some nearby marker, it's managing things. Where does the threading come in? just have the things talk back and forth by passing 'self' to whatever needs to respond...no threads will mess up on this, I've run 18 monsters at once with this method without a hint of a hickup. They were to come 3-6 at a time, that was just testing. Keep the state (not meaning 'state' meaning, variables describing behavior) on the individual monster, and it will be responsible for the condition of it's own thread as is basic OOP

I've read this thread carefully several times and the solutions and opinions discussed, while all true in a particular context, aren't very relevant to the original issue. This problem could be made irrelevant with a *very* slight shift in the method of controlling the monsters. This is an improper application of linear thinking (threading as something that must be managed manually) into what should be the simplest of object oriented application.

Like I said, nothings been really wrong so far. At least not that I can see. I just would rather see a working mod than a demoralizing cobweb of confusion.
I am sure there are tonnes of ways to do the task I commented on (and I already found a solution for it) but I don't see why wanting to start a thread or fork manually is an "improper application of linear thinking". It's as simple as asking the computer to "call these x functions simultaneously", which I am sure is a very reasonable request even in object-oriented algorithmic design.
User avatar
Mandi Norton
 
Posts: 3451
Joined: Tue Jan 30, 2007 2:43 pm

Post » Wed Jun 20, 2012 8:04 am

Good to hear you found a solution that works :D It's the manual part I was finding silly. If you (mymonster[myindex] as mymonsterscript).Dostuff() then there's no apearance of threading issues, each monster is neatly given it's own thread :D (If you want the master node to talk back to each monster, have it return 'self' or something like that, the 'thread' reference is assigned and tracked automatically). A nice and clean solution encapsulated for you. The threads are threads that were there anyways, the script instances of the enemies.

I always look forward to seeing new scripted encounter work. It's tricky to get it to have an impact on the actual fight, and fun when it does. Can't wait to see yours in action :D
User avatar
Amber Ably
 
Posts: 3372
Joined: Wed Aug 29, 2007 4:39 pm

Post » Wed Jun 20, 2012 5:17 pm

Good to hear you found a solution that works :biggrin: It's the manual part I was finding silly. If you (mymonster[myindex] as mymonsterscript).Dostuff() then there's no apearance of threading issues, each monster is neatly given it's own thread :biggrin: (If you want the master node to talk back to each monster, have it return 'self' or something like that, the 'thread' reference is assigned and tracked automatically). A nice and clean solution encapsulated for you. The threads are threads that were there anyways, the script instances of the enemies.

I always look forward to seeing new scripted encounter work. It's tricky to get it to have an impact on the actual fight, and fun when it does. Can't wait to see yours in action :biggrin:
Well actually, I wasn't talking to monsters. I was talking to lower level abstractions (with invisible actors and all) that do things to monsters. I find myself having to rely on these hacky coding strategies to get the control I want that isn't readily made available by this SDK.

I ain't really at the point of level-design or encounters yet. I am still trying cleaning up a number of features. From what I've seen in other threads, it appears combat a.i. is quite broken, so I am just going have to make several sets of NPC's each with 1 spell that has a script that thinks for them (hopefully).
User avatar
louise hamilton
 
Posts: 3412
Joined: Wed Jun 07, 2006 9:16 am


Return to V - Skyrim