Re: how does 'shared' affect member variables?

2015-05-09 Thread bitwise via Digitalmars-d-learn

On Sat, 09 May 2015 21:32:42 -0400, Mike n...@none.com wrote:

it looks like what you are trying to implement is what `synchronized`  
already provides:   
http://ddili.org/ders/d.en/concurrency_shared.html#ix_concurrency_shared.synchronized


Mike


Yes, but synchronized uses a mutex. Spin locks can perform better in  
situations where there won't be much contention for the lock.


  Bit


Re: how does 'shared' affect member variables?

2015-05-09 Thread bitwise via Digitalmars-d-learn

On Sat, 09 May 2015 15:38:05 -0400, Mike n...@none.com wrote:


On Saturday, 9 May 2015 at 18:41:59 UTC, bitwise wrote:

Also, I wasn't able to find any thorough documentation on shared, so if  
someone has a link, that would be helpful.




Here are a few interesting links:

Iain Buclaw (lead developer for GDC) with his interpretation:
http://forum.dlang.org/post/mailman.739.1431034764.4581.digitalmar...@puremagic.com

Andrei Alexandrescu highlighting a critical flaw with `shared`
http://forum.dlang.org/post/lruc3n$at1$1...@digitalmars.com

The truth about shared
http://p0nce.github.io/d-idioms/#The-truth-about-shared

Interesting deprecation warning in latest compiler (See compiler output):
http://goo.gl/EGvK72

But I don't know what the semantics are *supposed* to be, and I get the  
impression noone else knows either.  I'll be watching this thread myself  
to see if someone can provide some insight.


Mike


So it seems that although it's not properly implemented, it's still not  
completely benign, right?


I am trying to create a shared queue/array of delegates that run on the  
main thread. I don't know if D's 'shared' semantics will affect it or not,  
and whether or not casting to/from shared will cause problems with 'cas'  
or 'atomicStore'


Would the following code work as expected?

A simplified example:

struct SpinLock {
private int _lock = 0;

void lock() {
while(!cas(cast(shared(int)*)_lock, 0, 1)) {}
}
void unlock() {
atomicStore(*cast(shared(int)*)_lock, 0);
}
}

struct LockGuard(T) {
private T* _lock;

this(ref T lock) {
_lock = lock;
_lock.lock();
}
~this() {
_lock.unlock();
}
}

class App {
public:
@property public static App instance() {
return _instance;
}
this() {
assert(!_instance);
_instance = this;
}
~this() {
_instance = null;
}

void run(void delegate() dg) {
auto lk = LockGuard!SpinLock(_lock);
_actions.insertBack(dg);
}
void update()
{
auto lk = LockGuard!SpinLock(_lock);

foreach(act; _actions)
act();

_actions.clear();
}
package:
__gshared App _instance = null;

SpinLock _lock;
Array!(void delegate()) _actions;
}


Thread1:
App.instance.run({ doSomething1(); });

Thread2:
App.instance.run({ doSomething2(); });

Main Thread:
App app = new MyAppType();
while(true) {
app.update();
}


Thanks,
  Bit


Re: how does 'shared' affect member variables?

2015-05-09 Thread anonymous via Digitalmars-d-learn

On Saturday, 9 May 2015 at 18:41:59 UTC, bitwise wrote:

What does 'shared' do to member variables?


Makes them `shared`. :P

It makes sense to me to put it on a global variable, but what 
sense does it make putting it on a member of a class?


Globals are not the only way to pass data to other threads. E.g., 
you can std.concurrency.send a shared Object:



import core.thread: thread_joinAll;
import std.concurrency;
class C {int x;}
void main()
{
auto c = new shared C;
c.x = 1;
auto tid = spawn(() {
receive(
(shared C c) {c.x = 2;}
);
});
send(tid, c);
thread_joinAll();
assert(c.x == 2);
}


That shared C could come from a class/struct member, of course.

What happens if you try to access a member of a class/struct 
instance from another thread that is not marked 'shared'?


I think you're not supposed to be able to do that.


Re: how does 'shared' affect member variables?

2015-05-09 Thread anonymous via Digitalmars-d-learn

On Saturday, 9 May 2015 at 19:59:58 UTC, tcak wrote:
Stupidly, shared variables' value cannot be increased/decreased 
directly. Compiler says it is deprecated, and tells me to use 
core.atomic.atomicop. You will see this as well.


How's that stupid? Sounds like the compiler is doing its job 
guarding you from races.


Hey compiler! I know 100% that no other thing will be touching 
this variable.


Informing the compiler about this is done by casting shared away.


Re: how does 'shared' affect member variables?

2015-05-09 Thread bitwise via Digitalmars-d-learn

On Sat, 09 May 2015 15:59:57 -0400, tcak t...@gmail.com wrote:
If a variable/class/struct etc is not shared, for variables and struct,  
you find their initial value. For class, you get null.


For first timers (I started using shared keyword more than 2 years ago),  
do not forget that: a shared method is all about saying that this method  
is defined for shared object. So, do not get confused. It happened to me  
a lot.


Bad part of shared is that, you will be repeating it again, and again,  
and again, and again, everywhere. So, try to be patient if you are going  
to be using it for a long time.


Stupidly, shared variables' value cannot be increased/decreased  
directly. Compiler says it is deprecated, and tells me to use  
core.atomic.atomicop. You will see this as well. Hey compiler! I know  
100% that no other thing will be touching this variable.



using the SpinLock and LockGuard from my code above, I created a working  
test case. It works as expected, with no shared keyword on anything. The  
variable App._instance is __gshared, but that's about all.


///
import spinlock;
import std.stdio;
import std.concurrency;
import std.container;
import core.thread;

class App
{
SpinLock _lock;
Array!(void delegate()) _actions;

__gshared App _instance = null;

this() {
assert(!_instance);
_instance = this;
}

~this() {
_instance = null;
}

@property public static App instance() {
return _instance;
}

void run(void delegate() dg) {
auto lk = LockGuard!SpinLock(_lock);
_actions.insertBack(dg);
writeln(queued delegate);
}

void update()
{
writeln(updating);

auto lk = LockGuard!SpinLock(_lock);

foreach(act; _actions)
act();

_actions.clear();
}
}

void WorkerThread()
{
writeln(started worker, going to sleep);

Thread.sleep(500.msecs);

App.instance.run({
writeln(running delegate queued from thread);
});
}

void main()
{
App app = new App();

Thread workerThread = new Thread(WorkerThread).start();

int ms = 0;

while(ms  1000)
{
app.update();
Thread.sleep(100.msecs);
ms += 100;
}

workerThread.join();
}

//

OUTPUT:

updating
started worker, going to sleep
updating
updating
updating
updating
queued delegate
updating
running delegate queued from thread
updating
updating
updating
updating

//

No null references or 'init' values. A little confused now, but at least  
it works.


Finally, I tested to see if the lock was actually working:

void WorkerThread()
{
writeln(worker aquiring lock);
App.instance._lock.lock();
writeln(worker aquired lock);
App.instance._lock.unlock();
}

void main()
{
App app = new App();

writeln(main locked);
App.instance._lock.lock();

Thread workerThread = new Thread(WorkerThread).start();

writeln(main sleeping);
Thread.sleep(2.seconds);
writeln(main woke);
App.instance._lock.unlock();
writeln(main unlocked);

workerThread.join();
}

As expected, output was:

main locked
main sleeping
worker aquiring lock
main woke
main unlocked
worker aquired lock



And no 'shared' in sight. So now I'm confused as to when it has the affect  
that you were describing with null/init.


  Bit


Re: how does 'shared' affect member variables?

2015-05-09 Thread Mike via Digitalmars-d-learn

On Saturday, 9 May 2015 at 20:17:59 UTC, bitwise wrote:

On Sat, 09 May 2015 15:38:05 -0400, Mike n...@none.com wrote:


On Saturday, 9 May 2015 at 18:41:59 UTC, bitwise wrote:

Also, I wasn't able to find any thorough documentation on 
shared, so if someone has a link, that would be helpful.




Here are a few interesting links:

Iain Buclaw (lead developer for GDC) with his interpretation:
http://forum.dlang.org/post/mailman.739.1431034764.4581.digitalmar...@puremagic.com

Andrei Alexandrescu highlighting a critical flaw with `shared`
http://forum.dlang.org/post/lruc3n$at1$1...@digitalmars.com

The truth about shared
http://p0nce.github.io/d-idioms/#The-truth-about-shared

Interesting deprecation warning in latest compiler (See 
compiler output):

http://goo.gl/EGvK72

But I don't know what the semantics are *supposed* to be, and 
I get the impression noone else knows either.  I'll be 
watching this thread myself to see if someone can provide some 
insight.


Mike


So it seems that although it's not properly implemented, it's 
still not completely benign, right?


I am trying to create a shared queue/array of delegates that 
run on the main thread. I don't know if D's 'shared' semantics 
will affect it or not, and whether or not casting to/from 
shared will cause problems with 'cas' or 'atomicStore'


Would the following code work as expected?



I'm not sure if it would or no, as I haven't used these features 
of D before, but it looks like what you are trying to implement 
is what `synchronized` already provides:  
http://ddili.org/ders/d.en/concurrency_shared.html#ix_concurrency_shared.synchronized


Mike


Re: how does 'shared' affect member variables?

2015-05-09 Thread Mike via Digitalmars-d-learn

On Saturday, 9 May 2015 at 18:41:59 UTC, bitwise wrote:

Also, I wasn't able to find any thorough documentation on 
shared, so if someone has a link, that would be helpful.




Here are a few interesting links:

Iain Buclaw (lead developer for GDC) with his interpretation:
http://forum.dlang.org/post/mailman.739.1431034764.4581.digitalmar...@puremagic.com

Andrei Alexandrescu highlighting a critical flaw with `shared`
http://forum.dlang.org/post/lruc3n$at1$1...@digitalmars.com

The truth about shared
http://p0nce.github.io/d-idioms/#The-truth-about-shared

Interesting deprecation warning in latest compiler (See compiler 
output):

http://goo.gl/EGvK72

But I don't know what the semantics are *supposed* to be, and I 
get the impression noone else knows either.  I'll be watching 
this thread myself to see if someone can provide some insight.


Mike


Re: how does 'shared' affect member variables?

2015-05-09 Thread tcak via Digitalmars-d-learn

On Saturday, 9 May 2015 at 18:41:59 UTC, bitwise wrote:

What does 'shared' do to member variables?

It makes sense to me to put it on a global variable, but what 
sense does it make putting it on a member of a class? What 
happens if you try to access a member of a class/struct 
instance from another thread that is not marked 'shared'?


Also, I wasn't able to find any thorough documentation on 
shared, so if someone has a link, that would be helpful.


 Thanks
   Bit


If a variable/class/struct etc is not shared, for variables and 
struct, you find their initial value. For class, you get null.


For first timers (I started using shared keyword more than 2 
years ago), do not forget that: a shared method is all about 
saying that this method is defined for shared object. So, do not 
get confused. It happened to me a lot.


Bad part of shared is that, you will be repeating it again, and 
again, and again, and again, everywhere. So, try to be patient if 
you are going to be using it for a long time.


Stupidly, shared variables' value cannot be increased/decreased 
directly. Compiler says it is deprecated, and tells me to use 
core.atomic.atomicop. You will see this as well. Hey compiler! I 
know 100% that no other thing will be touching this variable.