使用多线程在 GNU C 中使用写入函数是不是安全

Posted

技术标签:

【中文标题】使用多线程在 GNU C 中使用写入函数是不是安全【英文标题】:is it safe to use Write Function in GNU C using multiple threads使用多线程在 GNU C 中使用写入函数是否安全 【发布时间】:2012-06-30 11:29:20 【问题描述】:

将来自多个线程的函数调用写入同一个套接字

安全吗? 我们想在它们之间添加同步吗? 会不会引起类似的问题 应用程序从网络层到应用程序层的写入/读取延迟

我们正在使用 GNU C++ 库 Linux Redhat 环境中的 GCC 4

这是一个服务器端进程,其中服务器和客户端之间只有 1 个套接字连接 服务器和客户端位于 2 台不同的机器上 数据从服务器发送到客户端 客户端到服务器

问题1-当服务器向客户端发送数据时(多个线程通过同一个单套接字向客户端写入数据)但是从某些线程写入的数据没有到达客户端它甚至没有到达网络层同一台机器(Tcpdump 没有那个数据)

问题 2-当客户端向服务器发送数据时,客户端发送的数据显示在服务器的 TCPdump 中未收到服务器应用程序,该服务器应用程序使用“读取”和“选择”函数从单个线程从套接字读取循环

我们无法确定发生这些问题的模式我们认为当有这么多多个线程写入同一个套接字时会发生这种情况我们没有同步写入函数希望操作系统正在处理同步

【问题讨论】:

它是“安全的”,因为您的程序格式正确,但您在套接字上看到的结果可能不是您所期望的。 @KerrekSB:这是一个奇怪的评论。从这个意义上说,任何线程不安全的程序都可以称为“安全”,不是吗? @NedBatchelder:当然不是。例如,一个依赖于静态缓冲区进行内部状态保持的函数只是不是线程安全的,而同时多次调用它的程序只是定义不明确。相比之下,同时调用write 的程序不会自动定义错误。 Socket send concurrency guarantees的可能重复 Are parallel calls to send/recv on the same socket valid?的可能重复 【参考方案1】:

write()是系统调用,不是库函数,系统调用一般保证是原子的。

【讨论】:

是的,不是真的。系统调用保证是原子的(并且在某种意义上是“安全的”,它既不会崩溃也不会破坏您的数据),但不能保证两个线程同时提交(原子地)的数据被传输原子地:interesting read。另请注意,writesend 在技术上允许写入比您要求的少,在这种情况下,您必须继续进行第二次写入操作,无论如何都会丧失所有原子性。【参考方案2】:

在多个线程中使用 write() 是不安全的。不能保证输出不会混在一起。一次写入可以将其一半的字节放入套接字,然后另一次写入可以开始将其放入字节。如果您需要确保每次写入都是连续写入的(很难想象不需要这种保证),那么您需要一个锁或其他一些同步方法。

【讨论】:

@samira:它肯定会导致你描述的问题,但不能说同步是否是原因。 在访问函数时,您可以使用互斥锁,这样一次只有一个线程在访问该函数... 没有互斥体会导致读取问题吗?有时写入的数据在 6 分钟后在 tcpdump 上可见 我不认为这是正确的。 write() 是系统调用,不是库函数,系统调用一般保证是原子的。我从未见过它在任何地方都说 write() 不是原子的。 @EJP:你应该把这个写成另一个答案。【参考方案3】:

未指定哪个write 调用首先完成。上下文切换可能会在第一条指令处停止两次写入中的任何一次。这可能导致任意排序。 write 或内核对此无能为力。这是一个根本性的问题。

您的数据将以未指定的顺序写入,您可能无法接受。

【讨论】:

以上是关于使用多线程在 GNU C 中使用写入函数是不是安全的主要内容,如果未能解决你的问题,请参考以下文章

linux下c语言简单实现写日志函数(多线程安全)

C ++如果一个线程写入一旦完成就会切换一个布尔值,那么在另一个线程的循环中读取该布尔值是不是安全?

在写入该变量的唯一线程中使用 memory_order_relaxed 加载原子变量是不是安全?

在线程中使用 std::string 函数是不是安全? (c++)

KafkaConsumer 对于多线程访问 pyspark 是不安全的

C++ 是不是有任何线程安全可以写入(比没有锁的线程安全类似物更快)组件?