查看: 118|回复: 2

C++ 中文周刊 第80期

[复制链接]

3

主题

6

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2022-9-20 16:48:42 | 显示全部楼层 |阅读模式
从reddit/hackernews/lobsters/meetingcpp知乎等等摘抄一些c++动态
周刊项目地址|在线地址 |知乎专栏 |腾讯云+社区
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等
可以贴在下一期草稿里 草稿链接
2022 0916
<hr/>资讯

标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 2022-09-14 第167期
cppcon 2022还在进行中。视频放了几个。没看。有参与者说今年不太行。我去年还没怎么看。看视频信息量太低了。得看PPT然后找视频看。最近没啥空。周末有时间可以看看
文章


  • Did you know that C++23 added stacktrace library?
打印堆栈支持。看代码
#include <stacktrace>
#include <iostream>

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

int main() {
  return foo();
}
可算支持了 - C++20 Modules Status Report
各个编译器Modules支持的状态进展介绍

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

  • Use-after-freedom: MiraclePtr
  • Pointer Safety Ideas
之前介绍过。介绍了谷歌浏览器团队在解决指针问题的一些实践。实现了很多,但是有些文档不可见。
也介绍了其他方案的实现,比如这个unowned_ptr
代码难找就没有深入研究。不过讨论还是值得一看的。我后面整理一下

  • 如何高效解决 C++内存问题,Apache Doris 实践之路|技术解析
介绍Sanitizer

  • 用户态操作系统之七 Seastar的文件操作
  • 用户态操作系统之八 Seastar的coroutine支持
seastar代码走读

  • 使用协程需要注意的问题(二)
注意co_await的阻塞语义,永远超时导致不能使用

  • Lua GC算法并行化探讨
四舍五入等于c的东西。可以看个热闹

  • Non-standard containers in C++
各种容器介绍,比如folly::fbvector, boost::small_vector等等。感兴趣的可以看看

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

  • Integrating C++ header units into Office using MSVC (1/n)
office团队要用module,这是msvc团队的一些探索

  • Is there any meaningful way to compare two Time Travel Debugging positions?
介绍msvc调试的。没用过不了解,有没有懂的给讲讲

  • The case of the recursively-acquired non-recursive lock, and how to avoid the unintentional reentrancy
代码长这样
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

  • Integer Conversions and Safe Comparisons in C++20
标准库提供了新函数来更友好的判断整数大小,不用自己写那些符号转换逻辑了
比如
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;
  }
}

  • Unsigned comparisons in AVX2/SSE: a quick note
VPSUBUSB    z, x, y

VPMINUB     z, x, y
VPCMPEQB    w, z, x我不太懂。不评价

  • Escaping strings faster with AVX-512
用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/

  • The case of the APC that never arrives
这段代码有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;
}

  • Serializing asynchronous operations in C++/WinRT
  • Creating a manual-start C++/WinRT coroutine from an eager-start one, part 1
  • Creating a lazy-start C++/WinRT coroutine from an eager-start one, part 2
讲协程的。说来惭愧我还不是很懂。就不介绍了
视频


  • C++ Weekly - Ep 341 - std format vs lib {fmt}
简单来说只有clang编译器支持std::format
开源项目需要人手


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


  • less 一个vector实现
  • alpaca 一个编码库
工作招聘

寒冬了。保佑我不被开

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

使用道具 举报

8

主题

14

帖子

30

积分

新手上路

Rank: 1

积分
30
发表于 2022-9-20 16:49:02 | 显示全部楼层
cppcon有两个国人讲的推荐看一下一个讲基于编译期反射的序列化库,另外一个讲module
回复

使用道具 举报

3

主题

10

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2022-9-20 16:49:54 | 显示全部楼层
好家伙,asteria
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表