为什么这段c++代码没有同步?
Why is this piece of C++ code not synchronized
我正在学习编写多线程应用程序。因此,尽管使用互斥锁,但每当我希望线程访问甚至是简单的共享资源时,我都会遇到麻烦。
例如,考虑以下代码:using namespace std;
mutex mu;
std::vector<string> ob;
void addSomeAValues(){
mu.lock();
for(int a=0; a<10; a++){
ob.push_back("A" + std::to_string(a));
usleep(300);
}
mu.unlock();
}
void addSomeBValues(){
mu.lock();
for(int b=0; b<10; b++){
ob.push_back("B" + std::to_string(b));
usleep(300);
}
mu.unlock();
}
int main() {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
thread t0(addSomeAValues);
thread t1(addSomeBValues);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
t0.join();
t1.join();
//Display the results
cout << "Code Run Complete; results: n";
for(auto k : ob){
cout << k <<endl;
}
//Code running complete, report the time it took
typedef std::chrono::duration<int,std::milli> millisecs_t;
millisecs_t duration(std::chrono::duration_cast<millisecs_t>(end-start));
std::cout << duration.count() << " milliseconds.n";
return 0;
}
当我运行程序时,它的行为不可预测。有时,A0-9和B0-9的值打印到控制台没有问题,有时有分割错误和崩溃报告,有时,A0-3 &给出了B0-5。
如果我错过了一个核心同步问题,请帮助
编辑:经过大量有用的反馈后,我将代码更改为#include <iostream>
#include <string>
#include <vector>
#include <mutex>
#include <unistd.h>
#include <thread>
#include <chrono>
using namespace std;
mutex mu;
std::vector<string> ob;
void addSomeAValues(){
for(int a=0; a<10; a++){
mu.lock();
ob.push_back("A" + std::to_string(a));
mu.unlock();
usleep(300);
}
}
void addSomeBValues(){
for(int b=0; b<10; b++){
mu.lock();
ob.push_back("B" + std::to_string(b));
mu.unlock();
usleep(300);
}
}
int main() {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now() ;
thread t0(addSomeAValues);
thread t1(addSomeBValues);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now() ;
t0.join();
t1.join();
//Display the results
cout << "Code Run Complete; results: n";
for(auto k : ob){
cout << k <<endl;
}
//Code running complete, report the time it took
typedef std::chrono::duration<int,std::milli> millisecs_t ;
millisecs_t duration( std::chrono::duration_cast<millisecs_t>(end-start) ) ;
std::cout << duration.count() << " milliseconds.n" ;
return 0;
}
但是有时我得到以下输出:
*** Error in `/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment':
double free or corruption (fasttop): 0x00007f19fc000920 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80a46)[0x7f1a0687da46]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x402dd4]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x402930]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x402a8d]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x402637
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x402278]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x4019cf]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x4041e3]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x404133]
/home/soliduscode/eclipse_workspace/CppExperiment/Debug/CppExperiment[0x404088]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xb29f0)[0x7f1a06e8d9f0]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7f8e)[0x7f1a060c6f8e]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7f1a068f6e1d]
更新,解决方案
对于我遇到的问题(即:不可预测的程序执行以及间歇性的损坏投诉转储),通过将-lpthread作为eclipse构建的一部分(在项目设置下),所有问题都得到了解决。
我正在使用c++ 11。奇怪的是,至少对我来说,这个程序在编译时没有发出一个我还没有链接到pthread的投诉。
所以对于任何使用c++ 11, std::thread和linux的人,确保你链接到pthread,否则你的程序运行时将非常不可预测,并且会有bug。
如果你打算使用线程,我建议至少做一点不同的工作。
现在,一个线程获得互斥锁,完成它要做的所有事情(包括睡眠3000微秒),然后退出。然后另一个线程基本上做同样的事情。在这种情况下,线程基本上没有完成任何积极的工作,反而完成了相当多的消极工作(同步代码等)。
你当前的代码在异常方面几乎是不安全的——如果一个异常被抛出到你的一个线程函数中,互斥锁不会被解锁,即使那个线程不能再执行。
最后,现在,您公开了一个互斥锁,并将其留给所有访问相关资源的代码来正确使用互斥锁。我更倾向于集中互斥锁,使其异常安全,并且大多数代码可以完全忽略它。
// use std::lock_guard, if available.
class lock {
mutex &m
public:
lock(mutex &m) : m(m) { m.lock(); }
~lock() { m.unlock(); }
};
class synched_vec {
mutex m;
std::vector<string> data;
public:
void push_back(std::string const &s) {
lock l(m);
data.push_back(s);
}
} ob;
void addSomeAValues(){
for(int a=0; a<10; a++){
ob.push_back("A" + std::to_string(a));
usleep(300);
}
}
这也意味着,如果(例如)您决定在将来使用无锁(或最小锁)结构,您应该只修改synched_vec
,而不是使用它的所有其他代码。同样,通过将所有互斥锁处理保存在一个地方,可以更容易地获得正确的代码,并且如果您确实发现了错误,则更容易确保您已经修复了它(而不是查看所有客户机代码)。
问题中的代码运行时没有任何分段错误(添加头并将睡眠替换为我的系统的睡眠)。
这段代码有两个问题,可能导致意外的结果:每个线程在其完全执行期间锁定互斥锁。这将阻止另一个线程运行。两个线程不是并行运行的!在您的情况下,您应该只在访问vector时进行锁定。
你的结束时间点是在创建线程之后,而不是在它们完成执行之后。当两个线程都是
join
时,两个线程都完成了。
带头文件、同步睡眠和修复两个错误的可编译代码
#include <mutex>
#include <string>
#include <vector>
#include <thread>
#include <iostream>
std::mutex mu;
std::vector<std::string> ob;
void addSomeAValues(){
for(int a=0; a<10; a++){
mu.lock();
ob.push_back("A" + std::to_string(a));
mu.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}
void addSomeBValues(){
for(int b=0; b<10; b++){
mu.lock();
ob.push_back("B" + std::to_string(b));
mu.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}
int main() {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
std::thread t0(addSomeAValues);
std::thread t1(addSomeBValues);
t0.join();
t1.join();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
//Display the results
std::cout << "Code Run Complete; results: n";
for(auto k : ob){
std::cout << k << std::endl;
}
//Code running complete, report the time it took
typedef std::chrono::duration<int,std::milli> millisecs_t;
millisecs_t duration(std::chrono::duration_cast<millisecs_t>(end-start));
std::cout << duration.count() << " milliseconds.n";
return 0;
}
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 如何为以下代码进行进程同步
- 将阻止同步代码转换为异步
- 如何从C 代码中检测Intel快速同步的存在
- 在Windows下同步C++代码的API失败
- 如何从另一个线程的 cpp 代码同步调用 qml 信号处理程序
- 此代码是否正确同步
- “std::mutex”和“std::lock”是否保证处理器间代码中的内存同步
- 为什么这段c++代码没有同步?
- 没有多线程的c++套接字不同步/并行代码
- 当一个线程正在编写另一个线程可能同时执行的代码时,如何在ARM上同步
- 带有互锁操作的线程同步在Visual Studio 2013 c++原生代码中挂起
- 设置C++代码中while循环的执行速率以进行实时同步