February 26, 2015
On 2/26/15 11:57 AM, Andrei Alexandrescu wrote:
> On 2/26/15 8:51 AM, Steven Schveighoffer wrote:
>> As talked about before, running dtors in the originating thread can
>> solve this problem.
>
> Yah, that will solve the nonatomic reference counting. What do you think
> about http://forum.dlang.org/thread/mcllre$1abs$1@digitalmars.com?

I saw that, it sounds reasonable. I have to mull over what it means.

I think possibly a better solution is to have a "finalize" function, similar to how tango does it, so the dtor is only called from destroy/delete, and the finalize method is called from the GC.

-Steve

February 26, 2015
On 2/26/15 12:56 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> On Thursday, 26 February 2015 at 16:51:30 UTC, Steven Schveighoffer wrote:
>> As talked about before, running dtors in the originating thread can
>> solve this problem.
>
> This probably implies forcibly destroying objects whose creating thread
> terminated.

I don't think so, those objects can just be destroyed by the GC-collection running thread. If the thread is no longer present, there can't be a race.

-Steve
February 26, 2015
On 2/26/15 12:56 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> On Thursday, 26 February 2015 at 16:51:30 UTC, Steven Schveighoffer wrote:
>> As talked about before, running dtors in the originating thread can
>> solve this problem.
>
> This probably implies forcibly destroying objects whose creating thread
> terminated.

However, this has to be done carefully. For instance, you have to run dtors on next allocation, or when thread terminates, because if you do it inside stop-the-world signal handler, you still potentially have a race.

-Steve
February 26, 2015
On Thursday, 26 February 2015 at 16:57:51 UTC, Andrei Alexandrescu wrote:
> On 2/26/15 8:51 AM, Steven Schveighoffer wrote:
>> As talked about before, running dtors in the originating thread can
>> solve this problem.
>
> Yah, that will solve the nonatomic reference counting. What do you think about http://forum.dlang.org/thread/mcllre$1abs$1@digitalmars.com?
>
> Andrei

class BazingaException : Exception {

    RefCount!Stuff reallyImportantStuff;

    // ...

}

void main() {
    auto t = new Thread({
        RefCount!Stuff s = ...;
        throw new BazingaException(s);
    });

    t.start();
    t.join();
}
February 26, 2015
On Thursday, 26 February 2015 at 18:04:11 UTC, Steven Schveighoffer wrote:
> I think possibly a better solution is to have a "finalize" function, similar to how tango does it, so the dtor is only called from destroy/delete, and the finalize method is called from the GC.

Ugh, so you still have to identify objects before releasing the memory?

Put all objects that need cleanup on a separate GC heap then, to reduce impact.
February 26, 2015
On 2/26/15 12:54 PM, deadalnix wrote:
> On Thursday, 26 February 2015 at 16:57:51 UTC, Andrei Alexandrescu wrote:
>> On 2/26/15 8:51 AM, Steven Schveighoffer wrote:
>>> As talked about before, running dtors in the originating thread can
>>> solve this problem.
>>
>> Yah, that will solve the nonatomic reference counting. What do you
>> think about http://forum.dlang.org/thread/mcllre$1abs$1@digitalmars.com?
>>
>> Andrei
>
> class BazingaException : Exception {
>
>      RefCount!Stuff reallyImportantStuff;
>
>      // ...
>
> }
>
> void main() {
>      auto t = new Thread({
>          RefCount!Stuff s = ...;
>          throw new BazingaException(s);
>      });
>
>      t.start();
>      t.join();
> }

Could you please walk me through what the matter is here. Thanks. -- Andrei

February 26, 2015
On Thursday, 26 February 2015 at 18:08:28 UTC, Steven Schveighoffer wrote:
> On 2/26/15 12:56 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> On Thursday, 26 February 2015 at 16:51:30 UTC, Steven Schveighoffer wrote:
>>> As talked about before, running dtors in the originating thread can
>>> solve this problem.
>>
>> This probably implies forcibly destroying objects whose creating thread
>> terminated.
>
> I don't think so, those objects can just be destroyed by the GC-collection running thread. If the thread is no longer present, there can't be a race.

That's true. However, what if the destructors access global (thread-local) variables? Is that already disallowed?
February 26, 2015
On 2/26/15 4:40 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> On Thursday, 26 February 2015 at 18:08:28 UTC, Steven Schveighoffer wrote:
>> On 2/26/15 12:56 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?=
>> <schuetzm@gmx.net>" wrote:
>>> On Thursday, 26 February 2015 at 16:51:30 UTC, Steven Schveighoffer
>>> wrote:
>>>> As talked about before, running dtors in the originating thread can
>>>> solve this problem.
>>>
>>> This probably implies forcibly destroying objects whose creating thread
>>> terminated.
>>
>> I don't think so, those objects can just be destroyed by the
>> GC-collection running thread. If the thread is no longer present,
>> there can't be a race.
>
> That's true. However, what if the destructors access global
> (thread-local) variables? Is that already disallowed?

Hm... I don't know. Is it "disallowed?" I don't think so (a simple test would suffice), but if any code exists today that does it, it's very very wrong :) I would suspect that such code should be banned.

-Steve
February 26, 2015
On 2015-02-26 21:07:26 +0000, Andrei Alexandrescu said:

> On 2/26/15 12:54 PM, deadalnix wrote:
>> On Thursday, 26 February 2015 at 16:57:51 UTC, Andrei Alexandrescu wrote:
>>> On 2/26/15 8:51 AM, Steven Schveighoffer wrote:
>>>> As talked about before, running dtors in the originating thread can
>>>> solve this problem.
>>> 
>>> Yah, that will solve the nonatomic reference counting. What do you
>>> think about http://forum.dlang.org/thread/mcllre$1abs$1@digitalmars.com?
>>> 
>>> Andrei
>> 
>> class BazingaException : Exception {
>> 
>> RefCount!Stuff reallyImportantStuff;
>> 
>> // ...
>> 
>> }
>> 
>> void main() {
>> auto t = new Thread({
>> RefCount!Stuff s = ...;
>> throw new BazingaException(s);
>> });
>> 
>> t.start();
>> t.join();
>> }
> 
> Could you please walk me through what the matter is here. Thanks. -- Andrei

The exception is thrown by t.join() in another thread, after the originating thread died. Thus, obviously, it cannot be destructed in the originating thread as stated above. But everyone already know that.

But the example doesn't make one problem quite clear: Unless the GC destroys the exception in the thread join() was called, there can be a race. That's because join() moves the exception to another thread, and the thread that now owns the exception could make copies of that reallyImportantStuff and access the counter beyond the exception's lifetime. So it turns out that the GC heap needs call the exception's destructor in the thread calling join() to avoid races.

Additionally, if the old thread has leftover objects still not yet collected, they'll need to be destroyed in the thread calling join() too. Otherwise you might get races when the exception is destroyed.

So you could solve all that by changing of ownership for things originating from the worker thread to the thread that is calling join(). Or if no one calls join(), then you can destroy objects originating from the dead thread in any thread, as long as they are all destroyed *in the same thread* (because objects originating from the same thread might all points to the same thread-local reference counts).

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

February 27, 2015
On Thu, 26 Feb 2015 18:04:28 -0500, Steven Schveighoffer wrote:

>> That's true. However, what if the destructors access global (thread-local) variables? Is that already disallowed?
> 
> Hm... I don't know. Is it "disallowed?" I don't think so (a simple test would suffice), but if any code exists today that does it, it's very very wrong :) I would suspect that such code should be banned.

but what if i'm doing memory managing myself and i *know* that it's ok to use thread-locals in my destructor?