加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

为什么这段C代码不同步

发布时间:2020-12-16 05:03:52 所属栏目:百科 来源:网络整理
导读:我正在学习编写多线程应用程序.因此,即使使用互斥锁,我也希望我的线程能够访问简单的共享资源. 例如,考虑以下代码: using namespace std;mutex mu;std::vectorstring ob;void addSomeAValues(){ mu.lock(); for(int a=0; a10; a++){ ob.push_back("A" + std
我正在学习编写多线程应用程序.因此,即使使用互斥锁,我也希望我的线程能够访问简单的共享资源.

例如,考虑以下代码:

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,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,否则你的程序运行时将非常难以预测,并且有错误.

解决方法

如果你打算使用线程,我建议至少做一点不同的工作.

现在,一个线程获取互斥锁,完成它所做的一切(包括睡眠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,而不是修改使用它的所有其余代码.同样,通过将所有互斥锁处理保存在一个位置,可以更容易地获得正确的代码,如果找到错误,则更容易确保修复它(而不是查看所有客户端代码).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读