Want reasonable reference counting? Disable automatic sharing of immutable

Stanislav Blinov stanislav.blinov at gmail.com
Sat Nov 13 20:01:16 UTC 2021


On Saturday, 13 November 2021 at 14:34:43 UTC, Steven 
Schveighoffer wrote:

> Whether it does this or pushes it off to another thread is 
> incidental. The running of finalizers is a function of the GC, 
> not the caller.

:)

> The part you are not getting is that this is not something 
> being called by the pure code, it's being run by the GC.

```d
import someLibrary;
// someLibrary defines a module-global
// int threadLocal;

void main()
{
     someLibrary.threadLocal = () pure nothrow {
         return someLibrary.blah(42);
     } ();
     auto old = someLibrary.threadLocal;
     auto someInts = () pure { return new int[1000]; } ();
     assert(someLibrary.threadLocal == old);
}
```

That assert may fail. Or you may even crash before getting to it, 
and not with an `OutOfMemoryError`, but with a `FinalizeError`, 
depending to the value of `threadLocal`. Or it can be totally 
fine if the GC doesn't collect. What am I not getting?..

> Imagine it like a context switch to another thread that runs 
> the GC code, and then switches back to the pure code.

If I imagine that, the assert above should always hold. Because 
there should be no way that imaginary "another thread" would 
access main thread's `threadLocal`. Somehow, reality contradicts 
imagination.

> In fact, the GC could do this ALREADY, because it could use one 
> of the other threads that it has paused do the collection. But 
> it doesn't really make any difference conceptually which thread 
> runs it. One of those other threads could be in the middle of a 
> pure function.

Could be != is.

> It's similar to running some kernel code, or signal code -- 
> it's initiated by a separate entity, in this case the GC.
>
>> Unless that changed and GC isn't doing that anymore, that's a 
>> bug that's been open for some years now.
>
> It should be closed as invalid. Which bug is that?

https://issues.dlang.org/show_bug.cgi?id=19316

Feel free to close it as invalid, if the code above either:
- dies with an OutOfMemoryError
- passes the assert

regardless of value of `threadLocal`.

`someLibrary` can be this for testing:

```d
module someLibrary;

int threadLocal;

class Good
{
     int calc(int input) pure nothrow { return input * 2; }
}

class Bad {

     int calc(int input) pure nothrow { return input + 14; }

     ~this() {
         // I agree with Walter, dtors should always be nothrow,
         // alas current language allows this
         if (threadLocal == 56) throw new Exception("ugh");
         threadLocal = 0;
     }
}

int blah(int input) pure nothrow {
     if (input <= 25)
        return (new Good).calc(input);
     else
        return (new Bad).calc(input);
}
```

Contrived? Maybe. Feel free to substitute `threadLocal` with 
`errno`, and make a syscall in `Bad.~this`.


More information about the Digitalmars-d mailing list