Multithreading 不允许可变线程本地数据的别名

Multithreading 不允许可变线程本地数据的别名,multithreading,concurrency,alias,d,Multithreading,Concurrency,Alias,D,我是D新手,我正在编写一个简单的多线程服务器以供练习。在C中启动客户机处理程序线程的一个常见范例是将新接受()套接字的文件描述符传递到pthread_create()中,但D的std.concurrency.spawn()不允许我传递套接字,因为它是可变的,可以由两个线程访问 当然,我实际上并不想要一个不可变的套接字(这就是为什么我真的不想在主线程中强制转换它,除非我必须这样做)——我想要传入一个可变的套接字,并让它在主线程中超出作用域。我该怎么办?我应该(/can)使用tid.send让线程使

我是D新手,我正在编写一个简单的多线程服务器以供练习。在C中启动客户机处理程序线程的一个常见范例是将新接受()套接字的文件描述符传递到pthread_create()中,但D的std.concurrency.spawn()不允许我传递套接字,因为它是可变的,可以由两个线程访问

当然,我实际上并不想要一个不可变的套接字(这就是为什么我真的不想在主线程中强制转换它,除非我必须这样做)——我想要传入一个可变的套接字,并让它在主线程中超出作用域。我该怎么办?我应该(/can)使用
tid.send
让线程使用套接字吗?因为某种原因,我觉得那很笨重

我现在的代码:

void main() {
    Socket listener = new TcpSocket;
    ...
    for (;;) {
        Socket s = listener.accept();
        scope(exit) s.close();

        auto tid = spawn(&clientHandler, s);
    }
}

void clientHandler(Socket s) {
    ...
}

这将生成:错误:静态断言“不允许使用可变线程本地数据的别名”。。。从这里实例化:繁殖!(Socket)

这里的问题不是Socket,它是一个局部变量。它是clientHandler,您还没有显示它的声明,但很明显,它是线程本地的,正如它在错误消息中所说的,当每个接受的套接字都应该有一个新的线程时。提示是单词“alias”,它指的是&operator。

您需要将套接字转换为shared,然后再转换回clienthandler

auto tid = spawn(&clientHandler, cast(shared) s);

void clientHandler(shared Socket s) {
    Socket sock = cast(Socket)s;
    scope(exit)sock.close();
}
原因是,除非指定了
共享
,否则所有局部变量都是隐式线程局部变量,并且只有对共享或不可变的引用可以作为参数传递给
生成
(或
发送
),而按值传递的内容(没有引用和原语的结构)则可以


此外,您还应该将close int置于处理程序中,就像您当前的实现一样,套接字可能会在新生成的线程有机会运行之前关闭

对不起,我已经通过添加
clientHandler()
声明澄清了这个问题。这是一个在全局范围内声明的函数,所以我可能比我最初想象的更困惑,但我怀疑这是有问题的线程本地数据。@Dan好的,那是什么?不是套接字,除非scope()对它有影响,不管它做什么:我不是“d”专家。
scope(exit)
确保
s.close()
将在这个作用域的末尾被调用,就像Java中的
finally
关键字一样。诚然,在我添加它的地方没有什么意义,但是删除它或将它放在其他地方对编译错误没有影响。我读到它会自动转换为线程局部变量,但这不应该应用于函数,而且无论如何,用(我认为是局部的)lambda表达式替换函数别名也会导致相同的错误。还要注意,如果我用
字符串替换
clientHandler()
Socket
参数(字符串是不可变的),这编译得很好。我认为局部变量被提升为线程局部变量!工作得很好,感谢您提供的额外信息!这是做类似事情的惯用方法,还是有更好的方法?在D中转换感觉很明显我做错了什么(即与C相反)@Dan上次我(一年前)检查了
shared
的语义,如果没有很好的定义,我不知道这是否发生了变化,因为从那时起,这方面没有任何变化。但是整个D社区都在等待
shared
得到很好的定义。