C ++核心准则:并发和无锁编程

原文:https://www.modernescpp.com/index.php/c-core-guidelines-concurrency-and-lock-free-programming

今天,我完成了并发性规则,并直接继续进行无锁编程。是的,您已正确阅读:无锁编程。

在我特别写无锁编程之前,这是并发的最后三个规则。

CP.43:尽量减少在关键部分花费的时间

CP.44:请记住命名您的lock_guards和unique_locks

CP.50:定义一个mutex及其所保护的数据。synchronized_value<T>尽可能使用

我之所以简短,是因为这些规则非常明显。

CP.43:尽量减少在关键部分花费的时间

锁定互斥锁的时间越短,其他线程可以运行的时间就越多。查看条件变量的通知。如果您想查看整个程序,请阅读我以前的文章C ++核心准则:警惕条件变量的陷阱

void setDataReady(){

    std::lock_guard<std::mutex> lck(mutex_);

    dataReady = true;                                // (1)

    std::cout << "Data prepared" << std::endl;

    condVar.notify_one();

}

Mutex Mutex_在函数开始时被锁定,在函数结束时被解锁。这不是必需的。仅表达式dataReady = true(1)必须受到保护。

首先,std :: cout是线程安全的。C ++ 11标准保证每个字符都是按原子步骤并按正确顺序编写的。其次,通知condVar.notify_one()是线程安全的。

这是setDataReady函数的改进版本:

void setDataReady(){

    {  // Don't remove because of the lifetime of the mutex (1)

        std::lock_guard<std::mutex> lck(mutex_);

        dataReady = true;

    }                                                      (2)

    std::cout << "Data prepared" << std::endl;

    condVar.notify_one();             

}

CP.44:请记住命名您的lock_guards和unique_locks

我有点惊讶地读了这条规则。以下是准则中的示例:

unique_lock<mutex>(m1);

lock_guard<mutex> {m2};

lock(m1, m2);

该unique_lock和lock_guard是被创建并立即销毁只是临时工。该的std :: lock_guard或std:: unique_lock锁定其互斥它的构造和取消锁定在其析构函数。这种模式称为RAII。在此处阅读详细信息:垃圾收集:不用了,谢谢

我的小示例仅显示概念行为std :: lock_guard。它的大哥std :: unique_lock支持更多操作。

// myGuard.cpp

#include <mutex>

#include <iostream>

template <typename T>

class MyGuard{

  T& myMutex;

  public:

    MyGuard(T& m):myMutex(m){

      myMutex.lock();

  std::cout << "lock" << std::endl;

    }

    ~MyGuard(){

  myMutex.unlock();

      std::cout << "unlock" << std::endl;

    }

};

int main(){

  std::cout << std::endl;

  std::mutex m;

  MyGuard<std::mutex> {m};                        // (1)

  std::cout << "CRITICAL SECTION" << std::endl;  // (2)


  std::cout << std::endl;

}                                                // (3)

MyGuard在其构造函数和其析构函数中调用锁定和解锁。由于是临时的,因此对构造函数和析构函数的调用发生在第(1)行中。特别是,这意味着析构函数的调用发生在第(1)行,而不像通常那样发生在第(3)行。因此,第(2)行中的关键部分将不同步执行。

该程序的执行表明,“ unlock ”的输出在“ CRITICAL SECTION ” 的输出之前发生。

CP.50:定义一个mutex及其所保护的数据。synchronized_value<T>尽可能使用

中心思想是将互斥锁放入要保护的数据中。使用已经标准化的C ++,它看起来像这样:

struct Record {

    std::mutex m;  // take this mutex before accessing other members

    // ...

};

对于即将发布的标准,它可能看起来像这样,因为synchronized_value<T>不是当前C ++标准的一部分,而是可能成为即将发布的标准的一部分。

class MyClass {

    struct DataRecord {

      // ...

    };

    synchronized_value<DataRecord> data; // Protect the data with a mutex

};


根据Anthony Williams 的建议N4033:“ 基本思想是synchronized_value<T>存储类型T和互斥量的值。然后它公开了一个指针接口,这样对指针的取消引用会产生一个特殊的包装类型,该类型将互斥量锁定,并可以隐式转换为T用于读取,并转发分配给基础的赋值运算符的任何值以T进行写入。”

这意味着以下代码段中对的操作是线程安全的。

synchronized_value<std::string> s;

std::string readValue()

{

    return *s;

}

void setValue(std::string const& newVal)

{

    *s=newVal;

}

void appendToValue(std::string const& extra)

{

    s->append(extra);

}

现在开始一些完全不同方式:无锁编程。

无锁编程

首先,让我说说无锁编程最重要的元规则。

不要无锁编程

当然,您不相信我,但是基于我参加许多并发课程和研讨会的经验,这是我的第一条规则。老实说,我同意世界上许多最受赞赏的C ++专家的意见。以下是他们的演讲的主要声明和引用:

Herb Sutter:无锁编程就像玩刀一样。

Anthony Williams:“无锁编程是关于如何用脚射击自己。 ”

Tony Van Eerd:“无锁编码是您要做的最后一件事。”

Fedor Pikus:“ 编写正确的无锁程序更加困难。 ”

HaraldBöhm:“ 规则并不明显。 ”

这是语句和引用的图片:

你还是不相信我 使用C ++ 11,定义了内存顺序std :: memory_order_consume。七年后,官方用语是:“ 发布-使用订购的规范正在修订,memory_order_consume暂时不鼓励使用。 ”(memory_order

如果您知道自己做了什么,请考虑 准则CP.100中的ABA问题。

CP.100:除非绝对必要,否则不要使用无锁编程

C ++核心指南中的以下代码片段存在bug。

extern atomic<Link*> head; // the shared head of a linked list

Link* nh = new Link(data, nullptr);    // make a link ready for insertion

Link* h = head.load();                // read the shared head of the list

do {

    if (h->data <= data) break;        // if so, insert elsewhere

    nh->next = h;                      // next element is the previous head

} while (!head.compare_exchange_weak(h, nh));    // write nh to head or to h


找到错误并给我写一封电子邮件。如果您喜欢自己的名字,我将在下一篇文章中提及最佳问题分析。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容