我正在学习编写多线程应用程序。因此,即使使用互斥锁,我也希望我的线程能够访问简单的共享资源。
例如,请考虑以下代码:
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&amp;呈现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,否则你的程序运行时将非常难以预测,并且有错误。
答案 0 :(得分:3)
如果您打算使用线程,我建议至少做一些不同的工作。
现在,一个线程获取互斥锁,执行所有操作(包括休眠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
,而不是修改所有其余代码使用它。同样,通过将所有互斥锁处理保存在一个位置,可以更容易地获得正确的代码,如果找到错误,则更容易确保修复它(而不是查看所有客户端代码)。 / p>
答案 1 :(得分:0)
问题中的代码运行时没有任何分段错误(添加标题并用我的系统睡眠代替睡眠)。
但代码有两个问题,可能导致意外结果:
每个线程在完全执行期间锁定互斥锁。这可以防止其他线程运行。这两个线程没有并行运行!在您的情况下,您只应在访问向量时锁定。
您的结束时间点是在创建线程之后而不是在完成执行之后获取的。两个线程都完成,当它们都是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;
}