c++ 高并发队列的实现

JAVA如何进行CAS讲到java的队列时,讲到java中的CAS操作回顾下java中的cas,主要采用compareAndSet方法,如AtomicReference中所使用的:AtomicRefrence.java/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect
摘要由CSDN通过智能技术生成

JAVA如何进行CAS

讲到java的队列时,讲到java中的CAS操作
回顾下java中的cas,主要采用compareAndSet方法,如AtomicReference中所使用的:
AtomicRefrence.java

/**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(V expect, V update) {
   
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

unsafe.java


    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapObject(Object o, long offset,
                                                     Object expected,
                                                     Object x);
  • obj :包含要修改的字段对象;
  • offset :字段在对象内的偏移量;
  • expect : 字段的期望值;
  • update : 如果该字段的值等于字段的期望值,用于更新字段的新值;

compareAndSwapObject是一个本地方法,调用的c++的实现

// Unsafe.h
virtual jboolean compareAndSwapObject(::java::lang::Object *, jlong, ::java::lang::Object *, ::java::lang::Object *);

// natUnsafe.cc
static inline bool
compareAndSwap (volatile jobject *addr, jobject old, jobject new_val)
{
   
	jboolean result = false;
	spinlock lock;
  
  	// 如果字段的地址与期望的地址相等则将字段的地址更新
	if ((result = (*addr == old)))
    	*addr = new_val;
	return result;
}

// natUnsafe.cc
jboolean
sun::misc::Unsafe::compareAndSwapObject (jobject obj, jlong offset,
                     jobject expect, jobject update)
{
   
	// 获取字段地址并转换为字符串
	jobject *addr = (jobject*)((char *) obj + offset);
	// 调用 compareAndSwap 方法进行比较
    return compareAndSwap (addr, expect, update);
}

这段代码主要做的是:
1、通过对象的首地址跟字段在对象内的偏移量来获取字段的地址
2、判断字段地址是否与我们期望的地址相同,如果相同即更新新的地址

在java中,地址相同说明两个对象相同。

注意到c++源码中使用的 spinlock,其实现:


// Use a spinlock for multi-word accesses
class spinlock
{
   
  static volatile obj_addr_t lock;

public:

spinlock ()
  {
   
    while (! compare_and_swap (&lock, 0, 1))
      _Jv_ThreadYield ();
  }
  ~spinlock ()
  {
   
    release_set (&lock, 0);
  }
};
  
// This is a single lock that is used for all synchronized accesses if
// the compiler can't generate inline compare-and-swap operations.  In
// most cases it'll never be used, but the i386 needs it for 64-bit
// locked accesses and so does PPC32.  It's worth building libgcj with
// target=i486 (or above) to get the inlines.
volatile obj_addr_t spinlock::lock;

volatile关键字让编译器不进行优化,从而lock值每次都从内存中读取。

C++如何进行CAS

通过前半文的了解,我们知道c 提供的函数 compare_and_swap

bool compare_and_swap ( int *memory_location, int expected_value, int new_value)
{
   
    if (*memory_location == expected_value)
    {
   
        *memory_location = new_value;
        return true;
    }
    return false;
}

(1)GGC对CAS支持
GCC4.1+版本中支持CAS原子操作。

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...);
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...);

(2)Windows对CAS支持
Windows中使用Windows API支持CAS。

LONG InterlockedCompareExchange(
  LONG volatile *Destination,
  LONG          ExChange,
  LONG          Comperand
);

(3)C11对CAS支持
C11 STL中atomic函数支持CAS并可以跨平台。

template< class T >
bool atomic_compare_exchange_weak( std::atomic* obj,T* expected, T desired );

template< class T >
bool atomic_compare_exchange_weak( volatile std::atomic* obj,T* expected, T desired );

atomic_compare_exchange_weak当存储值时会发生失败情况,且返回false,所以通常采用while直至比对交换成功,相比使用aotmic_compare_exchange_strong会有更高的性能,而使用while也即是通常所说的自旋效果。

已有的c++ 无锁队列

1、生产级队列ConcurrencyQueue
这是我在生产中使用的,因为消费者可以采用wait方式监听队列消息进行消费,所以蛮方便的。

2、boost方案:
boost提供了三种无锁方案,分别适用不同使用场景。
boost::lockfree::queue是支持多个生产者和多个消费者线程的无锁队列。
boost::lockfree::stack是支持多个生产者和多个消费者线程的无锁栈。
boost::lockfree::spsc_queue是仅支持单个生产者和单个消费者线程的无锁队列,比boost::lockfree::queue性能更好。
Boost无锁数据结构的API通过轻量级原子锁实现lock-free,不是真正意义的无锁。
Boost提供的queue可以设置初始容量,添加新元素时如果容量不够,则总容量自动增长;但对于无锁数据结构,添加新元素时如果容量不够,总容量不会自动增长。

因为boost太大了,所以生产比较少用

自己造轮子

当我们能把一样东西做出来,说明我们才是真正的了解,所以多造轮子对自己有帮助。

RingBuffer 环形队列

在这里插入图片描述

数据结构

我们采用数组的线性空间来实现环形接口,当数据到达尾部时将其转回到0的位置重写入。
环形结构的容量位置从数组q[0] 到 q[max - 1]。
head表示队列头,tail表示队列尾,当(tail + 1) % max 即表示队列已满

算法

%max 取余 可以 通过位运算  head &  (max - 1),需要保证max是2的幂次方

RingBuffer实现

单消费者,单生产者

#pragma once

template<typename T>
class RingBuffer {
   
private:
	//队列大小
	unsigned int _size;
	//队列头部索引
	int _front;
	//队列尾部索引
	int _tail;
	//数据缓冲区
	T* _data;
public:
	RingBuffer(unsigned int size) :_size(size),_front(0), _tail(0) {
   
		_data = new T[size]
  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用epoll和线程池实现高并发服务器C++11代码示例: ```cpp #include <iostream> #include <thread> #include <vector> #include <queue> #include <mutex> #include <condition_variable> #include <sys/epoll.h> #include <unistd.h> #define MAX_EVENTS 100 #define THREAD_POOL_SIZE 10 std::mutex mtx; std::condition_variable cv; std::queue<int> taskQueue; void workerThread() { while (true) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [] { return !taskQueue.empty(); }); int fd = taskQueue.front(); taskQueue.pop(); // 处理任务,这里可以根据具体需求进行处理 lock.unlock(); // 继续监听其他事件 } } int main() { // 创建epoll句柄 int epoll_fd = epoll_create(1); if (epoll_fd == -1) { std::cerr << "Failed to create epoll" << std::endl; return 1; } // 创建线程池 std::vector<std::thread> threadPool; for (int i = 0; i < THREAD_POOL_SIZE; ++i) { threadPool.emplace_back(workerThread); } // 添加监听事件到epoll句柄 struct epoll_event event; event.events = EPOLLIN; event.data.fd = /* 监听的文件描述符 */; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, /* 监听的文件描述符 */, &event) == -1) { std::cerr << "Failed to add event to epoll" << std::endl; return 1; } // 开始监听事件 struct epoll_event events[MAX_EVENTS]; while (true) { int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (num_events == -1) { std::cerr << "Failed to wait for events" << std::endl; return 1; } for (int i = 0; i < num_events; ++i) { if (events[i].events & EPOLLIN) { // 处理读事件,将任务添加到任务队列 std::lock_guard<std::mutex> lock(mtx); taskQueue.push(events[i].data.fd); cv.notify_one(); } } } // 清理资源 close(epoll_fd); for (auto& thread : threadPool) { thread.join(); } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值