Wad*_*Wad 1 c unix multithreading solaris solaris-10
假设我已经打开dev/poll mDevPoll,我可以安全地调用这样的代码
struct pollfd tmp_pfd;
tmp_pfd.fd = fd;
tmp_pfd.events = POLLIN;
// Write pollfd to /dev/poll
write(mDevPoll, &tmp_pfd, sizeof(struct pollfd));
Run Code Online (Sandbox Code Playgroud)
...同时来自多个线程,或者我是否需要添加自己的同步原语mDevPoll?
它在理论上并不安全,即使它write()是完全线程安全的(除非存在实现错误......)。 根据 POSIXwrite()标准(重点是我的): .
该
write()函数应尝试将nbyte字节从指向的缓冲区写入buf与打开的文件描述符相关联的文件,fildes。...
返回值
成功完成后,这些函数应返回实际写入的字节数...
无法保证您不会得到 partial write(),因此即使每个单独的write()调用都是原子的,也不一定是完整的,因此您仍然可以获得交错的数据,因为可能需要多次调用write()才能完全写入所有数据。
在实践中,如果您只进行相对较小的write()调用,您可能永远不会看到 partial write(),“small”和“likely”是取决于您的实现的不确定值。
我经常交付的代码write()在打开的常规文件上使用未锁定的单个调用,O_APPEND以提高日志记录的性能 - 构建一个日志条目,然后write()通过一次调用构建整个条目。在 Linux 和 Solaris 系统上进行了将近几十年的操作后,我从未见过部分或交错的write()结果,即使许多进程写入同一个日志文件也是如此。但话又说回来,它是一个文本日志文件,如果write()确实发生了部分或交错的情况,则不会造成真正的损坏,甚至不会丢失数据。
但是,在这种情况下,您正在向内核结构“写入”少量字节。您可以/dev/poll在 Illumos.org 上挖掘 Solaris内核驱动程序源代码,并查看部分的可能性write()。我怀疑这实际上是不可能的 - 因为我刚刚回去查看了十年前我为我公司的软件库编写的多平台投票类。在 Solaris 上,它使用/dev/poll和解锁write()来自多个线程的调用。它已经运行了十年......
Solaris /dev/pool 设备驱动源码分析
(开放)Solaris 源代码可以在这里找到:http : //src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/io/devpoll.c#628
该dpwrite()函数是/dev/poll驱动程序中实际执行“写入”操作的代码。我使用引号是因为它根本不是真正的写操作 - 数据的传输不像内核中代表被轮询的文件描述符集的数据更新的那么多。
数据从用户空间复制到内核空间 - 到使用kmem_alloc(). 我看不到任何可能的方式可以是部分副本。要么分配成功,要么不成功。代码可以在做任何事情之前被中断,因为它等待对write()内核结构的独占访问。
之后,最后一个返回调用结束 - 如果没有错误,则整个调用被标记为成功,或者整个调用因任何错误而失败:
995 if (error == 0) {
996 /*
997 * The state of uio_resid is updated only after the pollcache
998 * is successfully modified.
999 */
1000 uioskip(uiop, copysize);
1001 }
1002 return (error);
1003}
Run Code Online (Sandbox Code Playgroud)
如果您深入研究 Solaris 内核代码,您会发现这uio_resid就是write()成功调用后返回的值。
所以这个电话肯定是要么全有要么全无。虽然当传入多个描述符时,在成功处理较早的描述符后,代码似乎有办法返回文件描述符上的错误,但代码似乎没有返回任何部分成功指示。
如果您一次只处理一个文件描述符,我会说/dev/pollwrite() 操作是完全线程安全的,并且几乎可以肯定的是,“写入”多个文件描述符的更新是线程安全的,因为没有明显的方法驱动程序返回部分write()结果。
Solaris 10声称符合POSIX标准.该write()函数不是POSIX允许非线程安全的少数几个系统接口之一,因此我们可以得出结论,在Solaris 10上,write()从一般意义上说,从两个或多个线程同时调用是安全的.
POSIX还指定write()那些在常规文件或符号链接上运行时效果相对于原子的函数.具体而言,它说
如果两个线程分别调用其中一个函数,则每个调用应该看到另一个调用的所有指定效果,或者没有一个.
如果你的写入被定向到一个常规文件,那么就足以得出结论你提出的多线程动作是安全的,因为它们不会相互干扰,并且一次调用中写入的数据不会与之混合在任何线程中由不同的调用写的.不幸的是,/dev/poll它不是常规文件,因此不直接适用于您.
您还应该知道,write()通常不需要传输单个调用中指定的完整字节数.因此,为了一般目的,必须准备通过使用循环在多个调用上传输所需的字节.Solaris可能提供超出POSIX表达的适用保证,可能特定于目标设备,但如果没有这样的保证,可以想象您的一个线程执行部分写入,而下一个写入由不同的线程执行.这很可能不会产生您想要或期望的结果.
| 归档时间: |
|
| 查看次数: |
1422 次 |
| 最近记录: |