[Issue 10108] Thread local slice to array literal references the same data

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri May 17 13:57:51 PDT 2013


http://d.puremagic.com/issues/show_bug.cgi?id=10108


Igor Stepanov <wazar.leollone at yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |wazar.leollone at yahoo.com


--- Comment #8 from Igor Stepanov <wazar.leollone at yahoo.com> 2013-05-17 13:57:50 PDT ---
(In reply to comment #7)
> Simplified example without __gshared:
> 
> import core.thread;
> 
> int[] arr = [1,2,3];
> 
> void main( ) {
>     int* p = arr.ptr;
>     auto thr = new Thread({assert(arr.ptr == p);}); // Should have failed.
>     thr.start();
>     thr.join();
> }

In other words implicit "thread local" modifier is not transitive.
Yes, all threads have a local copy of "arr symbol" and &arr differs in
different threads.
But all of this "local" symbols points to single array object. The problem lies
deeper than it seems.

struct Foo
{
  int[] arr;
}

Foo[] getFooArr()
{
   Foo[] ret;
   foreach(i; 1 .. 10)
   {
      Foo cur;
      foreach(j; 1 .. 5) 
      {
         cur.arr ~= j;
      }
      ret ~= cur;
   }
   return ret;
}

Foo[] arr = getFooArr();

Now foo points to the arr, each members of it points to array literal.
And if we want to create Foo[] is true TLS object, we must to set, that
1. arr must point to tls object (arr.ptr must be
thread_tls_start+arr_tls_offset)
2. for each i: arr[i].arr must point to tls object.
In other words
If compiler see ptr dereference expression (with * or []) it must know, is this
ptr is TLS. If it is TLS compiler must add to it value thread_tls_start,
otherwise - use it value as is.
This functional can be provided, if we declare transitive threadlocal storage
class (like shared) and implement special reference behaviour. (e.g.
dereference, casting and other.) for example:

theradlocal int[][] tls = [[1,2],[3,4],[5,6]];

int* getNthMthElemPointer(theradlocal int[][] a, int n, int m)
{
   return &ptr[n][m]; //implicit cast to non-tls pointer. returned value points
to elem it function caller thread
}

void main()
{
  int* p1 = getNthMthElemPointer(tls, 1, 1);
  theradlocal int* p2 = &tls[1][1];


  void threadFunc(int num)()
  {
    writeln(num, " shared ptr: ", p1);
    writeln(num, " thread local ptr: ", cast(int*)p2);
  }
  auto thr1 = new Thread(&threadFunc!1);
  thr1.start();
  auto thr2 = new Thread(&threadFunc!2);
  thr2.start();

  thr1.join();
  thr2.join();
}

therads will print same "shared ptr" value but different "thread local ptr"



However this future is disharmonious with language design I think.
Other way: disallow all of tls static initialized values.

shared int[] a = [1,2,3]; //OK
_gshared int[] b = [1,2,3]; //OK
const int[] c = [1,2,3]; //OK
int[] d = [1,2,3]; //Disallowed
int[] e;//OK

static this()
{
  e = [1,2,3]; //If e value will be allocated in heap this code doesn't break
type system.
}
The same applies to classes, pointers and associative arrays in future.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list