One of the interesting things that has happened with our concurrency model is that we have begun to rely on thread locals quite heavily. A lot of our API design patterns such as locale and web processing are based on thread local variables. Currently thread locals are simply a big Str:Obj map.
Given the role thread locals seem to be playing in our APIs and applications, I propose a new threadlocal keyword which allows us to define strongly typed thread local fields. It will work pretty similar to the ThreadStatic attribute in C#.
// old way
Thread.locals["web.req"] = req
WebReq req := Thread.locals["web.req"]
// new way
threadlocal WebReq req // declare field
Weblet.req // access like static field
Design issues:
threadlocal is only applicable to fields (not methods, types)
can be used in both classes and mixins
composable with any protection scope including readonly
not composable with abstract, const, final, native, virtual, override, static, once
has auto-generated accessor methods
can have user-defined accessor methods
calling convention is like static field access (must access with type, not instance)
storage location will use new threadlocal flag 0x00040000
storage get/set will use two new opcodes LoadThreadLocal and StoreThreadLocal
JVM emit will use ThreadLocal with appropriate casts
IL emit to be determined by Andy
Once this feature is implemented, I suggest we deprecate the Thread.locals method.
Barring any negative feedback, I will probably start this feature tomorrow night.
andyWed 23 Apr 2008
So how would your proposal look with this code:
class Foo
{
Void foo()
{
Thread.locals["foo"] = 15
}
}
class Bar
{
Int foo()
{
return Thread.locals["foo"] as Int
}
}
brianWed 23 Apr 2008
Just like a static field - it would be named within a type. So if we put it into Foo:
class Foo
{
threadlocal Int foo := 15
}
class Bar
{
Int foo() { return Foo.foo }
}
andyWed 23 Apr 2008
Yeah, I guess my reservation is you're tying that slot to particular type now. But maybe that actually makes more sense most of the time. Actually now that I think about it, I do like that.
But the case I keep thinking about is Weblet - where the threadlocals are actually defined in the implementation (wisp, tomcat, etc) - and now you've made it more complicated to decouple:
abstract class Weblet
{
new make()
{
req = (WebReq)Thread.locals["web.req"]
res = (WebRes)Thread.locals["web.res"]
}
...
}
tacticsWed 23 Apr 2008
Couldn't you bake it into the syntax to allow for something like:
class Foo {
threadlocal foo := 15
}
That way, the type can be inferred as usual from the constructor.
andyWed 23 Apr 2008
By convention we've said fields should be explicitly typed, which makes the code more readable and consistent. And I think Brian actually enforces that in the compiler.
jodastephenWed 23 Apr 2008
I wonder if this is still too low level.
Most applications have a notion of scoping for variables - request scope, session scope and application scope being typical examples. Using threadlocal seems to be a way to allow users to create scoped variables, but still require the user to do the work of determining request vs session vs application.
brianWed 23 Apr 2008
I'm not sure if I entirely follow that.
Many of Fan API's are defined to be thread scoped such as current locale. We also define that a WebReq scope is guaranteed to thread scoped (so effectively they are the same thing). That a key design pattern - APIs are thread scoped, and you map your application scopes to threads (such as a WebReq runs in its own thread). It is kind of something that has grown to be our convention, but it seems to be working really well.
jodastephenWed 23 Apr 2008
I suspect that we may have a terminology issue. Let me rephrase. Is it possible to get access to an object that represents the session (in a web environment). This object would have the lifecycle of HttpSession for example. Also, there might be a web level session and an application level session, linked but different.
How do you intend to handle this? Does the coder have to go to the WebReq and get a session object?
Another point is that a session object could be accessed by multiple threads at the same time (in a J2EE system). Since this kind of access is part of what fan tries to avoid, how do you solve the use case.
brianThu 24 Apr 2008
Yes - currently WebSession is accessed via a method on WebReq. How a WebSession is managed is through thread messaging (although it could be thru the namespace). So threads don't take out locks on an object like WebSession - they work with a copy and then when they are done they "check it back in". You can look at the code and see how this works.
The real issue is what happens when multiple threads are working with copies of the objects - they are lots of ways to deal with this from the database world. What Fan does right now for both namespaces and web sessions is the simple way - last guy wins. Obviously that needs to be enhanced to provide more options such as raise exception, merge, transactions, etc. Namespaces still need a lot of work.
I would characterize that problem as concurrency, which to me is a higher level problem and very different issue than threadlocal storage. Threadlocal is really about how we want to design Fan APIs. Do we want pass objects around or just keep thread local "globals".
I was going to plunge into this feature tonight, but I still have an uneasy feeling about adding this complexity to the language. I kind of feel like maybe we ought to wait and get some more experience under our belt, so I'll probably chew off something else next.
AndyDentThu 25 Nov 2010
What about considering the inverse approach, as taken in the "D" programming language, of making all variables thread-local by default and requiring special attribution to make them shared?
using actorLoc
using magic
class Foo
{
@Magic { kind = ActorLocal<||> }
private Int int := 5
}
brianFri 26 Nov 2010
What about considering the inverse approach, as taken in the "D" programming language, of making all variables thread-local by default and requiring special attribution to make them shared?
Interesting idea, but I think at this point we wouldn't want to introduce a breaking change like that. Plus I think for familiarity to Java programmers having static const fields shared as true const, immutable instances is pretty useful. I use them all over the place myself to share immutable data structures between threads.
brian Wed 23 Apr 2008
One of the interesting things that has happened with our concurrency model is that we have begun to rely on thread locals quite heavily. A lot of our API design patterns such as locale and web processing are based on thread local variables. Currently thread locals are simply a big Str:Obj map.
Given the role thread locals seem to be playing in our APIs and applications, I propose a new
threadlocal
keyword which allows us to define strongly typed thread local fields. It will work pretty similar to the ThreadStatic attribute in C#.Design issues:
Once this feature is implemented, I suggest we deprecate the Thread.locals method.
Barring any negative feedback, I will probably start this feature tomorrow night.
andy Wed 23 Apr 2008
So how would your proposal look with this code:
brian Wed 23 Apr 2008
Just like a static field - it would be named within a type. So if we put it into Foo:
andy Wed 23 Apr 2008
Yeah, I guess my reservation is you're tying that slot to particular type now. But maybe that actually makes more sense most of the time. Actually now that I think about it, I do like that.
But the case I keep thinking about is Weblet - where the threadlocals are actually defined in the implementation (wisp, tomcat, etc) - and now you've made it more complicated to decouple:
tactics Wed 23 Apr 2008
Couldn't you bake it into the syntax to allow for something like:
class Foo {
}
That way, the type can be inferred as usual from the constructor.
andy Wed 23 Apr 2008
By convention we've said fields should be explicitly typed, which makes the code more readable and consistent. And I think Brian actually enforces that in the compiler.
jodastephen Wed 23 Apr 2008
I wonder if this is still too low level.
Most applications have a notion of scoping for variables - request scope, session scope and application scope being typical examples. Using threadlocal seems to be a way to allow users to create scoped variables, but still require the user to do the work of determining request vs session vs application.
brian Wed 23 Apr 2008
I'm not sure if I entirely follow that.
Many of Fan API's are defined to be thread scoped such as current locale. We also define that a WebReq scope is guaranteed to thread scoped (so effectively they are the same thing). That a key design pattern - APIs are thread scoped, and you map your application scopes to threads (such as a WebReq runs in its own thread). It is kind of something that has grown to be our convention, but it seems to be working really well.
jodastephen Wed 23 Apr 2008
I suspect that we may have a terminology issue. Let me rephrase. Is it possible to get access to an object that represents the session (in a web environment). This object would have the lifecycle of HttpSession for example. Also, there might be a web level session and an application level session, linked but different.
How do you intend to handle this? Does the coder have to go to the WebReq and get a session object?
Another point is that a session object could be accessed by multiple threads at the same time (in a J2EE system). Since this kind of access is part of what fan tries to avoid, how do you solve the use case.
brian Thu 24 Apr 2008
Yes - currently WebSession is accessed via a method on WebReq. How a WebSession is managed is through thread messaging (although it could be thru the namespace). So threads don't take out locks on an object like WebSession - they work with a copy and then when they are done they "check it back in". You can look at the code and see how this works.
The real issue is what happens when multiple threads are working with copies of the objects - they are lots of ways to deal with this from the database world. What Fan does right now for both namespaces and web sessions is the simple way - last guy wins. Obviously that needs to be enhanced to provide more options such as raise exception, merge, transactions, etc. Namespaces still need a lot of work.
I would characterize that problem as concurrency, which to me is a higher level problem and very different issue than threadlocal storage. Threadlocal is really about how we want to design Fan APIs. Do we want pass objects around or just keep thread local "globals".
I was going to plunge into this feature tonight, but I still have an uneasy feeling about adding this complexity to the language. I kind of feel like maybe we ought to wait and get some more experience under our belt, so I'll probably chew off something else next.
AndyDent Thu 25 Nov 2010
What about considering the inverse approach, as taken in the "D" programming language, of making all variables thread-local by default and requiring special attribution to make them shared?
This was described in Concurrency in the D Programming Language
ivan Thu 25 Nov 2010
I've just got actor locals for myself :P
brian Fri 26 Nov 2010
Interesting idea, but I think at this point we wouldn't want to introduce a breaking change like that. Plus I think for familiarity to Java programmers having static const fields shared as true const, immutable instances is pretty useful. I use them all over the place myself to share immutable data structures between threads.
go4 Wed 14 Dec 2011
Just remind this topic.
A quick implementation like this:
it's more readable:
It also solve the private scope