- 博客(76)
- 收藏
- 关注
原创 高并发栈(stack)数据结构的无锁实现和超详细分析过程
一、创建无锁栈1. 实现无锁栈的基本结构众所周知,栈是一个后进先出(LIFO)的数据结构,栈只需要直接访问栈首元素即可,因此,可以使用最简单的单向链表来实现栈。向栈中加入元素的步骤为:创建一个新的节点;将新节点的next指针指向栈首(head元素);将head指向新节点;上述过程在单线程中很完美,但是在多线程中就有可能发生数据竞争:线程1将新节点1的next指向head之后,发生线程切换,线程2将自己的节点2的next指向head,并将head指向节点2。此时线程1切换回来继续执行,将新的h
2020-09-04 16:37:23 1391 2
原创 基于细粒度锁的高并发队列的超详细实现和分析过程
本文内容一、前言二、线程安全的队列的实现1. 使用锁和条件变量来实现线程安全的队列2. 使用细粒度锁和条件变量来实现线程安全的队列使用细粒度锁来实现队列的高并发性引入条件变量来实现队列的可等待接口三、总结一、前言最近在看《C++ Concurrency In Action 2nd》,发现里面一节基于锁来实现高并发的队列讲解的非常棒,并且里面体现了很多细节,而且还给出了一些实现高并发数据结构的指导方针,因此觉得很不错,就在此边翻译边讲解一下。本教程从比较粗糙的设计开始,一步一步转向更精细的设计,..
2020-08-22 18:11:44 663 1
原创 C++11内存模型完全解读-从硬件层面和内存模型规则层面双重解读
acquire-release:release-sequence rule:指线程1中对原子变量进行store操作,线程2对此原子变量执行RMW操作,线程3对此原子变量页执行RMW操作,线程4与线程3类似…线程n对此原子变量执行load操作或者RMW操作。其中上述所有的store操作都是用的release、acq_rel、seq_cst语义,而所有的load作都用的acquire、acq_rel、seq_cst、consume语义,且除了最后一个线程中的RMW不能用relaxed语义外,其他任何中间线程
2020-08-18 16:43:11 4464 14
转载 git上传某个commit到远程仓库
原文:https://blog.csdn.net/COCOLI_BK/article/details/128254877。
2023-04-25 13:54:16 144
转载 VSCode中设置静态IP(转载)
https://blog.csdn.net/readiay/article/details/50866709
2021-06-15 16:55:42 555 1
原创 cygwin放到右键菜单
1. 在~/.bashrc中添加:_T=${_T//\\//}if [[ $_T == "" ]]; then _T=${HOME}ficd "${_T}"2. 添加到右键菜单:下载Context Menu Editor,使用管理员权限打开(Win10的话要启用兼容模式,使用Win7的管理员模式打开):其中,Path填写:"C:\cygwin64\bin\mintty.exe" -i /Cygwin-Terminal.ico /bin/env _T=%V /bin/
2021-02-18 19:52:06 267 1
原创 对C++多重继承中函数名称查找的理解
class A1 { public: virtual void P() const = 0; void print() const { std::cout << "A1\n"; }; }; class B1 : public A1 { public: void P() const override final { print(); } void print() const { std::cout << "B1\n"; } }; class B.
2020-10-07 20:30:01 245
原创 volatile变量与原子变量的差异
原子变量:能够保证其上的所有操作都是原子性的,不可分割的;使用默认的内存序模型的原子变量可以保证编译器或者硬件不会对相关代码或指令进行重排;volatile变量:不保证其上的所有操作都是原子性的;编译器可能会对相关代码进行重排,或者CPU硬件进行指令重排;告诉编译器不会优化那些冗余代码:int x;x = 20; // 使用volatile后,编译器不会把这一句优化掉x = 30;auto y = x; // 使用volatile后,编译器不会把这一句优化掉,但是如果是原子变量
2020-10-06 22:31:22 993
原创 C++学习笔记-lambda表达式
lambda表达式的值捕获或者引用捕获只能捕获lambda表达式的作用域内可见的非静态局部变量,包括形参;在构造lambda表达式的时候,尽量不要使用默认的值捕获或者默认的引用捕获,而是直接将需要捕获的变量放到捕获列表中;在类中使用lambda捕获成员变量时,无法通过将成员变量加入到捕获列表里面去捕获,可以通过默认的值捕获的方式捕获成员变量:class A{private: int m;public: void f() { auto r = [](){std::cout ..
2020-10-05 14:52:19 229
原创 C++学习笔记-右值引用、移动语义和完美转发
std::move()只是做了一次强制类型转换,将实参转成右值类型,并不做其他任何动作;如果想用std::move()实现真正的移动操作,那么传入的实参类型一定不能是常量类型,不然通过std::move()强转出来的类型也仍然带有常量属性,导致调用构造函数时调用的是复制构造函数,而不是移动构造函数;当定义的函数的形参是右值类型的时候,只能传入一个右值给这个函数,不能传一个左值给这个函数;std::move()是无条件的将实参转成右值类型(当然会保留常量属性),而std::forward..
2020-10-04 17:55:12 189
原创 C++学习笔记-智能指针
如果想用堆内存指针,则最好首选std::unique_ptr,它的大小与内置类型指针相同,且性能也几乎与内置类型指针差不多。如果内置类型指针对你来说足够小或者足够快,那么std::unique_ptr几乎可以肯定也能满足你的要求。不过,如果不使用默认的析构器,而是自定义析构器,则大小可能会变化。当自定义析构器是普通函数时,则大小至少加上函数指针的尺寸,如果自定义析构器是函数对象,则带来的尺寸变化取决于该函数对象中存储了多少状态。无状态的函数对象(如无捕获的lambda表达式)不会浪费任何存储空间。因此,..
2020-09-30 16:36:23 570
原创 C++学习笔记-现代C++功能
当函数的形参是按值传递时,实参的顶层const属性以及引用属性在传入时都会被忽略,但是实参的底层const不会被忽略。当形参是指针或者左值引用时(T&),实参的顶层const或底层const都不会被忽略,但是实参的引用属性仍然被忽略。当形参是万能引用时(T&&),实参的顶层const和底层const也不会被忽略,但是实参的引用属性被忽略,此外,尽管此时形参是右值引用,但是传入的实参是左值时,形参会变成左值引用,传入的实参是右值时,形参也会变成右值引用。此外,volatile如同c..
2020-09-29 14:33:51 172
原创 TCP/IP网络编程学习笔记(十三)
IO完成端口模型的实现要点:创建一个具有重叠(Overlapped)属性的socket(可以用WSASocket()来创建);创建一个IO完成端口对象(简称CP对象)句柄(使用CreateIOCompletionPort()创建);创建多个线程(比如可以创建线程池),并将上述CP对象句柄传递给创建的线程(作为线程函数的参数传递进去,CP对象将通过该句柄分配到线程)。然后,在线程中调用GetQueuedCompletionStatus()进行阻塞(注意,结束时一定要主动关闭线程句柄或者使用对应的..
2020-09-26 13:06:20 102
原创 TCP/IP网络编程学习笔记(十二)
重叠IO模型(Overlapped IO)中,IO操作本身是异步的,与调用IO函数的线程无关。也就是说,调用IO的线程只是发起IO操作,IO操作本身是由其他线程完成的,调用IO的线程可以同时干其他事情。不过,当确认IO操作是否完成时,默认还是需要调用IO的线程来确认。如果添加了回调函数,也就是IO操作完成后自动执行一个后处理函数,此时这个后处理函数也是由刚才发起IO请求的线程来执行的,并且只有当发起IO请求的线程执行了等待函数(比如WaitForSingleObjectEx(),WaitForMulti..
2020-09-23 15:52:03 82
原创 TCP/IP网络编程学习笔记(十一)
Windows下类似与Linux下的epoll异步通知IO模型(不是异步IO模型)是基于WSAEventSelect实现的(还有一种WSAAsyncSelect也能实现,不过一般用于UI);WSAEventSelect实现的异步IO通知模型的过程:使用WSACreateEvent()创建一个手动重置事件(注意结束时要用WSACloseEvent()来销毁这个手动重置事件);使用WSAEventSelect()将一个句柄(比如socket句柄)与上一步创建的手动重置事件进行绑定,调用此函数时..
2020-09-22 15:55:54 81
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人