前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 中文周刊 第80期

C++ 中文周刊 第80期

作者头像
王很水
发布2022-09-23 08:58:28
2380
发布2022-09-23 08:58:28
举报

C++ 中文周刊 第80期

reddit/hackernews/lobsters/meetingcpp知乎等等摘抄一些c++动态

周刊项目地址|在线地址 |知乎专栏

腾讯云+社区

弄了个qq频道,手机qq点击进入

欢迎投稿,推荐或自荐文章/软件/资源等

可以贴在下一期草稿里 草稿链接

2022 0916


资讯

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 2022-09-14 第167期

cppcon 2022还在进行中。视频放了几个。没看。有参与者说今年不太行。我去年还没怎么看。看视频信息量太低了。得看PPT然后找视频看。最近没啥空。周末有时间可以看看

文章

打印堆栈支持。看代码

#include <stacktrace>
#include <iostream>

int foo() {
  std::cout << std::stacktrace::current();
  return {};
}

int main() {
  return foo();
}

可算支持了

各个编译器Modules支持的状态进展介绍

标准库的std::optional是不支持T&和void的。作者说了下自己可能会用到这个场景,标准库应该加上

之前介绍过。介绍了谷歌浏览器团队在解决指针问题的一些实践。实现了很多,但是有些文档不可见。

也介绍了其他方案的实现,比如这个unowned_ptr

代码难找就没有深入研究。不过讨论还是值得一看的。我后面整理一下

介绍Sanitizer

seastar代码走读

注意co_await的阻塞语义,永远超时导致不能使用

四舍五入等于c的东西。可以看个热闹

各种容器介绍,比如folly::fbvector, boost::small_vector等等。感兴趣的可以看看

写了个工具验证gcc产出的代码对不对,具体就是验证gimple IR。我不太懂。感兴趣可以看看

office团队要用module,这是msvc团队的一些探索

介绍msvc调试的。没用过不了解,有没有懂的给讲讲

代码长这样

struct WidgetTracker : IWidgetChangeNotificationSink
{
    /* other stuff not relevant here */

    /// IWidgetChangeNotificationSink
    STDMETHODIMP OnCurrentWidgetChanged();

private:
    WRL::ComPtr<IWidget> m_currentWidget;
    std::mutex m_mutex;
};

HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
    auto guard = std::lock_guard(m_mutex);
    RETURN_IF_FAILED(GetCurrentWidget(&m_currentWidget));
    return S_OK;
}

OnCurrentWidgetChanged是个回调,如果m_currentWidget变了就会被调用

问题在于OnCurrentWidgetChanged被调用这个m_mutex锁住的瞬间,m_currentWidget析构,结果又触发一次OnCurrentWidgetChanged,导致死锁

这个问题根源在于锁锁不住comptr,无法避免递归调用。

解决方法也很简单,拷贝一份对象就行了。

HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
    WRL::ComPtr<IWidget> widget; // 可能别人在用它
    auto guard = std::lock_guard(m_mutex);
    RETURN_IF_FAILED(GetCurrentWidget(&widget));
    m_currentWidget.Swap(widget);
    return S_OK;
}

作者之前讨论过一段类似的代码,用的,shared_ptr, 也有相同的问题

class ThingManager
{
private:
  std::mutex things_lock_;
  std::vector<std::shared_ptr<Thing>> things_;

public:
  void AddThing(std::shared_ptr<Thing> thing)
  {
    std::lock_guard guard(things_lock_);
    things_.push_back(std::move(thing));
  }

  void RemoveThingById(int32_t id)
  {
    std::lock_guard guard(things_lock_);
    auto it = std::find_if(things_.begin(), things_.end(),
      [&](auto&& thing)
      {
        return thing->id() == id;
      });
    if (it != things_.end()) {
      things_.erase(it);
    }
  }
};

class SuperThing : Thing
{
private:
  ThingManager& manager_;
  int32_t helper_id_ = 0;

public:
  SuperThing(ThingManager& manager) :
    manager_(manager)
  {
    auto helper = std::make_shared<Thing>();
    helper_id_ = helper->id();
    manager_.AddThing(helper);
  }

  ~SuperThing()
  {
    manager_.RemoveThingById(helper_id_);
  }
};

void test(ThingManager& manager)
{
  auto s = std::make_shared<SuperThing>(manager);
  auto id = s->id();
  manager.AddThing(s);
  s = nullptr; // 1

  manager.RemoveThingById(id); // 2
}

问题是相同的,同一个锁被锁两次。如何触发?首先SuperThing会在2 这行真正的析构,1那行只会引用计数-1 RemoveThingById(id)是会锁的,内部触发了SuperThing析构,然后又调用了manager_.RemoveThingById(helper_id_);,锁了同一个锁

你可能觉得这种代码写的有问题。这是锁和shared_ptr和坑爹析构三个同时引入引发的问题,我遇不到

解决方法也很简单。让这个shared_ptr活着,因为不知道哪个外部调用会用到这个shared_ptr

void RemoveThingById(int32_t id)
{
  std::shared_ptr removed_thing; // 求求你活着
  {
    std::lock_guard guard(things_lock_);
    auto it = std::find_if(things_.begin(), things_.end(), ...);
    if (it != things_.end()) {
      removed_thing = *it;
      things_.erase(it);
    }
  }
}

引用计数指针和锁的问题。这里打个问号。要注意

oldnewthing的博客真精彩,总能遇到各种莫名其妙的bug

标准库提供了新函数来更友好的判断整数大小,不用自己写那些符号转换逻辑了

比如

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool cmp_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept {
  static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>,
   "The integer comparison functions only "
   "accept standard and extended integer types.");
  if constexpr (is_signed_v<_Ty1> == is_signed_v<_Ty2>) {
    return _Left == _Right;
  } else if constexpr (is_signed_v<_Ty2>) {
    return _Left == static_cast<make_unsigned_t<_Ty2>>(_Right) && _Right >= 0;
  } else {
    return static_cast<make_unsigned_t<_Ty1>>(_Left) == _Right && _Left >= 0;
  }
}
VPSUBUSB	z, x, y

VPMINUB		z, x, y
VPCMPEQB	w, z, x

我不太懂。不评价

用avx处理字符串中的斜杠,比如my title is \"La vie\"

通常写法

  for (...) {
    if ((*in == '\\') || (*in == '"')) {
      *out++ = '\\';
    }
    *out++ = *in;
  }

sse/avx写法

 __m512i solidus = _mm512_set1_epi8('\\');
  __m512i quote = _mm512_set1_epi8('"');
  for (; in + 32 <= finalin; in += 32) {
    __m256i input = _mm256_loadu_si256(in);
    __m512i input1 = _mm512_cvtepu8_epi16(input);
    __mmask64 is_solidus = _mm512_cmpeq_epi8_mask(input1, solidus);
    __mmask64 is_quote = _mm512_cmpeq_epi8_mask(input1, quote);
    __mmask64 is_quote_or_solidus = _kor_mask64(is_solidus, is_quote);
    __mmask64 to_keep = _kor_mask64(is_quote_or_solidus, 0xaaaaaaaaaaaaaaaa);
    __m512i shifted_input1 = _mm512_bslli_epi128(input1, 1);
    __m512i escaped =
        _mm512_mask_blend_epi8(is_quote_or_solidus, shifted_input1, solidus);
    _mm512_mask_compressstoreu_epi8(out, to_keep, escaped);
    out += _mm_popcnt_u64(_cvtmask64_u64(to_keep));
  }

给我看困了

这里有个类似的https://branchfree.org/2019/03/06/code-fragment-finding-quote-pairs-with-carry-less-multiply-pclmulqdq/

这段代码有bug,不懂这几个API的可能看不懂

bool ShuttingDown = false;

void MainThread()
{
    DWORD id;
    auto hThread = CreateThread(nullptr, 0, WorkerThread,
                                nullptr, 0, &id); // succeeds

    BlahBlahBlah(); // do useful work

    // Time to clean up. Post an APC to the worker thread
    // to tell it that it's time to go home.
    QueueUserAPC(WakeWorker, hThread, 0); // succeeds

    WaitForSingleObject(hThread, INFINITE); // hangs

    CloseHandle(hThread);
}

void CALLBACK WakeWorker(ULONG_PTR)
{
    ShuttingDown = true;
}

DWORD CALLBACK WorkerThread(void*)
{
    // Do work until shut down.
    do
    {
        // All work is posted via APCs.
        SleepEx(INFINITE, TRUE);
    } while (!ShuttingDown);

    return 0;
}

简单来说SleepEx通过QueueUserAPC来唤醒,有一种场景,QueueUserAPC唤醒了,但是CreateThread执行的慢,导致SleepEx没收到通知,从而永远死锁

怎么解决这个问题?把do while循环改成while就行了。因为这种场景已经shutdown了,不应该执行sleep

DWORD CALLBACK WorkerThread(void*)
{
    // Do work until shut down.
    while (!ShuttingDown)
    {
        // All work is posted via APCs.
        SleepEx(INFINITE, TRUE);
    } 

    return 0;
}

讲协程的。说来惭愧我还不是很懂。就不介绍了

视频

简单来说只有clang编译器支持std::format

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

工作招聘

寒冬了。保佑我不被开

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

     This site is open source. [Improve this page](https://github.com/wanghenshui/cppweeklynews/edit/dev/posts/080.md).
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C++ 中文周刊 第80期
    • 资讯
      • 文章
        • 视频
          • 开源项目需要人手
            • 新项目介绍/版本更新
              • 工作招聘
                • 寒冬了。保佑我不被开
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档