cout是否同步/线程安全?

如何解决cout是否同步/线程安全?

| 通常,我假定流不同步,这取决于用户进行适当的锁定。但是,诸如library0之类的东西在标准库中是否得到特殊对待? 也就是说,如果多个线程正在写入
cout
,它们是否可以破坏
cout
对象?我了解,即使同步,您仍然会获得随机交错的输出,但这可以保证交错。也就是说,从多个线程使用
cout
是否安全? 该供应商依赖吗? gcc是做什么的? 重要提示:如果您说“是”,请提供某种参考,因为我需要某种证明。 我也不在乎底层的系统调用,它们很好,但是流在顶部增加了一层缓冲。     

解决方法

        C ++ 03标准对此没有任何说明。如果不能保证某事物的线程安全,则应将其视为不是线程安全的。 这里特别令人感兴趣的是“ 0”被缓冲的事实。即使保证对“ 5”的调用(或在特定实现中实现此效果的任何方法)是互斥的,缓冲区也可能由不同的线程共享。这将迅速导致流的内部状态损坏。 即使保证对缓冲区的访问是线程安全的,您认为这段代码还会发生什么?
// in one thread
cout << \"The operation took \" << result << \" seconds.\";

// in another thread
cout << \"Hello world! Hello \" << name << \"!\";
您可能希望此处的每一行相互排斥。但是实现如何保证呢? 在C ++ 11中,我们确实有一些保证。 FDIS在§27.4.1[iostream.objects.overview]中指出以下内容:   多个线程并不会同时访问同步(第27.5.3.4节)标准iostream对象的格式化和未格式化的输入(第27.7.2.1节)和输出(第27.7.3.1节)功能或标准C流   在数据竞赛中(第1.10节)。 [注意:用户仍然必须通过以下方式同步并发使用这些对象和流   多线程,如果他们希望避免交错字符。 —尾注] 因此,您不会受到损坏的流,但是如果您不希望输出成为垃圾,则仍然需要手动对其进行同步。     ,        这是一个很好的问题。 首先,C ++ 98 / C ++ 03没有“线程”的概念。因此,在那个世界上,这个问题毫无意义。 C ++ 0x呢?参见马丁尼奥的答案(我承认让我感到惊讶)。 C ++ 0x之前的具体实现如何?好吧,例如,这是来自GCC 4.5.2的
basic_streambuf<...>:sputc
的源代码(\“ streambuf \”标头):
 int_type
 sputc(char_type __c)
 {
   int_type __ret;
   if (__builtin_expect(this->pptr() < this->epptr(),true)) {
       *this->pptr() = __c;
        this->pbump(1);
        __ret = traits_type::to_int_type(__c);
      }
    else
        __ret = this->overflow(traits_type::to_int_type(__c));
    return __ret;
 }
显然,这不会执行锁定。
xsputn
也没有。这绝对是cout使用的streambuf的类型。 据我所知,libstdc ++不会对任何流操作进行锁定。我不会指望任何东西,因为那样会很慢。 因此,通过这种实现方式,很明显两个线程的输出可能会相互破坏(而不仅仅是交错)。 这段代码会破坏数据结构本身吗?答案取决于这些功能的可能相互作用。例如,如果一个线程试图刷新缓冲区而另一个线程试图调用
xsputn
或类似的东西,会发生什么。这可能取决于您的编译器和CPU如何决定对内存加载和存储进行重新排序。需要仔细分析才能确定。如果两个线程尝试同时修改同一位置,这也取决于您的CPU的工作。 换句话说,即使它在您当前的环境中正常运行,当您更新任何运行时,编译器或CPU时,它也可能会中断。 执行摘要:“我不会”。构建一个执行适当锁定的日志记录类,或移至C ++ 0x。 作为一种较弱的选择,您可以将cout设置为unbuffered。可能(尽管不能保证)会跳过与缓冲区有关的所有逻辑并直接调用
write
。尽管那可能会太慢了。     ,           C ++标准未指定写入流是否是线程安全的,但通常不是。 www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging 并且:C ++线程安全的标准输出流(cout,cerr,clog)是否安全? 更新 请查看@Martinho Fernandes的答案,以了解新标准C ++ 11对此的解释。     ,就像其他答案提到的那样,这肯定是特定于供应商的,因为C ++标准没有提及线程(C ++ 0x中的更改)。 GCC并未对线程安全性和I / O做出很多承诺。但是它所承诺的文档在这里: http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html#manual.intro.using.concurrency.io 关键的东西可能是:   __basic_file类型只是一个   周围的小包装的集合   C stdio层(同样,请参见链接   在结构下)。我们不锁定   自己,但只需通过   调用fopen,fwrite等。      因此,对于3.0,“   I / O安全的多线程”必须是   回答:“是您平台的C吗?   库线程安全的I / O吗?\“有些是   默认情况下,有些不是;许多报价   C的多种实现   权衡不同的图书馆   线程安全性和效率。你,   程序员,总是需要   注意多线程。      (例如,POSIX标准   需要C stdio FILE *操作   是原子的。符合POSIX的C   库(例如,在Solaris和   GNU / Linux)具有一个内部互斥体   序列化FILE * s上的操作。   但是,您仍然不需要做   像调用fclose(fs)这样的愚蠢的事情   在一个线程中,然后访问   fs在另一个。)      因此,如果您平台的C库是   线程安全,那么您的fstream I / O   操作将在   最低级别。对于更高级别   操作,例如操作   流中包含的数据   格式化类别(例如,设置   std :: ofstream内部的回调),   您需要保护诸如   任何其他关键共享资源。 我不知道在提到的3.0时间框架内是否有任何变化。 可以在以下位置找到MSVC的“ѭ12”线程安全文档:http://msdn.microsoft.com/zh-cn/library/c9ceah3b.aspx:   单个对象是线程安全的   从多个线程读取。对于   例如,给定对象A,它是安全的   从线程1和A读取A   同时线程2。      如果要写入单个对象   由一个线程,然后所有读取和   在同一对象上写入该对象   其他线程必须受到保护。对于   例如,给定对象A,如果线程   1正在写入A,则线程2必须   阻止从或中读取   写信给A。      读和写一个是安全的   一个类型的实例,即使另一个   线程正在读取或写入   相同类型的不同实例。   例如,给定的对象A和B   相同的类型,如果A为   被写在线程1和B是   在线程2中读取。      ...      iostream类      iostream类遵循相同的   规则和其他类别一样   例外。写一个   来自多个线程的对象。对于   例如,线程1可以在以下位置写入cout   与线程2同时进行。但是,   这可能会导致   两个线程混合在一起。      注意:从流缓冲区读取是   不被视为读操作。   应该认为是写   操作,因为这会改变   类的状态。 请注意,该信息适用于MSVC的最新版本(当前适用于VS 2010 / MSVC 10 /
cl.exe
16.x)。您可以使用页面上的下拉控件为MSVC的较早版本选择信息(该信息对于较早版本是不同的)。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-