C++ 线程实战案例解析

C++单例模式深度解析:从线程安全到工程实践 单例模式是软件设计中用于确保一个类只有一个实例并提供全局访问点的创建型模式。其核心原理在于通过私有化构造函数和提供静态访问方法,实现对实例数量的严格控制。这一模式的技术价值在于解决资源访问冲突和避免资源浪费,尤其在需要全局唯一资源管理器的场景下,如日志系统、配置管理、线程池等。在C++工程实践中,实现线程安全的单例需深入理解静态初始化顺序、内存模型等语言特性。从经典的懒汉式、饿汉式,到基于局部静态变量的Meyers‘ Singleton,再到利用std::call_once的现代实现,每种方案都需权衡懒加载 阅读详情

案例1: 最基础的生产者消费者模型

#include <stdio.h>      // 标准输入输出(printf)
#include <pthread.h>    // POSIX线程库(线程创建/互斥锁/条件变量)
#include <unistd.h>     // 睡眠函数(sleep)
#include <stdlib.h>     // 标准库(内存分配/退出等,此处暂未用到)
 
#define BUF_SIZE 3  // 缓冲区大小:最多存放3个数据
int g_buf[BUF_SIZE]; // 共享缓冲区:存储生产/消费的数据
int g_idx = 0;      // 缓冲区当前已存元素个数(共享资源,需互斥保护)
 
// 同步原语:互斥锁+两个条件变量(分别协调生产者/消费者)
pthread_mutex_t g_mutex;          // 互斥锁:保护共享资源(g_buf/g_idx)的排他访问
pthread_cond_t g_cond_prod;       // 生产者条件变量:缓冲区有空位时唤醒生产者
pthread_cond_t g_cond_cons;       // 消费者条件变量:缓冲区有数据时唤醒消费者
 
// 生产者线程函数:循环往缓冲区放入5个数据
// 参数:arg - 线程入参(此处未使用),返回值:线程退出状态(此处返回NULL)
void* producer(void* arg) {
    // 生产5个数据(循环5次)
    for (int i = 0; i < 5; i++) {
        // 1. 加互斥锁:保护共享资源(g_buf/g_idx),防止多线程同时修改
        //    加锁后,其他线程调用pthread_mutex_lock会阻塞,直到当前线程解锁
        pthread_mutex_lock(&g_mutex);
 
        // 2. 检查缓冲区是否满:如果满了,生产者需要等待消费者取数据
        //    注意:必须用while而非if!避免「虚假唤醒」(条件变量被唤醒后,条件可能已不满足)
        //    比如:多个生产者被唤醒时,缓冲区可能已被其他生产者占满
        while (g_idx == BUF_SIZE) {
            // pthread_cond_wait做两件事:
            //   a. 原子操作:解锁g_mutex + 阻塞当前线程,等待被唤醒
            //   b. 被唤醒后:继续从这个代码开始执行, 重新加锁g_mutex,然后退出wait继续执行
            pthread_cond_wait(&g_cond_prod, &g_mutex);
        }
 
        // 3. 生产数据:往缓冲区放入当前数值i
        g_buf[g_idx++] = i; // g_idx先赋值,再自增(等价于g_buf[g_idx]=i; g_idx++;)
        // 打印生产信息:pthread_self()获取当前线程ID,g_idx是当前缓冲区数据量
        printf("生产者[%ld]:放入%d,缓冲区数量=%d\n", pthread_self(), i, g_idx);
 
        // 4. 唤醒消费者:缓冲区已有数据,通知消费者可以取数据了
        //    pthread_cond_signal:唤醒等待该条件变量的任意一个线程(此处只有1个消费者)
        //    若有多个消费者,可用pthread_cond_broadcast唤醒所有
        pthread_cond_signal(&g_cond_cons);
 
        // 5. 解锁互斥锁:释放共享资源,让其他线程(消费者)可以访问
        pthread_mutex_unlock(&g_mutex);
        
        // 模拟生产耗时(比如生产一个数据需要1秒),让出CPU,让消费者有机会执行
        sleep(1);
    }
    // 线程正常退出,返回NULL
    return NULL;
}
 
// 消费者线程函数:循环从缓冲区取出5个数据
// 参数:arg - 线程入参(此处未使用),返回值:线程退出状态(此处返回NULL)
void* consumer(void* arg) {
    // 消费5个数据(与生产者生产数量一致)
    for (int i = 0; i < 5; i++) {
        // 1. 加互斥锁:保护共享资源,防止与生产者同时修改g_buf/g_idx
        pthread_mutex_lock(&g_mutex);
 
        // 2. 检查缓冲区是否空:如果空了,消费者需要等待生产者放数据
        //    同样用while避免虚假唤醒(比如多个消费者被唤醒时,缓冲区已空)
        while (g_idx == 0) {
            // 阻塞当前线程,等待生产者的唤醒信号(g_cond_cons)
            // 等待期间会自动解锁g_mutex,被唤醒后重新加锁
            pthread_cond_wait(&g_cond_cons, &g_mutex);
        }
 
        // 3. 消费数据:从缓冲区取出最后一个数据
        int val = g_buf[--g_idx]; // g_idx先自减,再赋值(等价于g_idx--; val=g_buf[g_idx];)
        // 打印消费信息:当前线程ID + 取出的数据 + 剩余缓冲区数量
        printf("消费者[%ld]:取出%d,缓冲区数量=%d\n", pthread_self(), val, g_idx);
 
        // 4. 唤醒生产者:缓冲区有空位了,通知生产者可以继续生产
        pthread_cond_signal(&g_cond_prod);
 
        // 5. 解锁互斥锁:释放共享资源,让生产者可以访问
        pthread_mutex_unlock(&g_mutex);
        
        // 模拟消费耗时(比如消费一个数据需要1秒),让出CPU,让生产者有机会执行
        sleep(1);
    }
    // 线程正常退出,返回NULL
    return NULL;
}
 
int main() {
    // 定义线程ID:分别存储生产者/消费者线程的ID
    pthread_t tid_prod, tid_cons;
 
    // 初始化同步原语:必须先初始化,才能使用
    // 第二个参数为NULL:使用默认属性
    pthread_mutex_init(&g_mutex, NULL);          // 初始化互斥锁
    pthread_cond_init(&g_cond_prod, NULL);       // 初始化生产者条件变量
    pthread_cond_init(&g_cond_cons, NULL);       // 初始化消费者条件变量
 
    // 创建线程
    // 参数:线程ID指针、线程属性(NULL=默认)、线程函数、函数入参(NULL)
    pthread_create(&tid_prod, NULL, producer, NULL); // 创建生产者线程
    pthread_create(&tid_cons, NULL, consumer, NULL); // 创建消费者线程
 
    // 等待线程结束:主线程阻塞,直到生产者/消费者线程执行完毕
    // 第二个参数为NULL:不接收线程的返回值
    pthread_join(tid_prod, NULL); // 等待生产者线程退出
    pthread_join(tid_cons, NULL); // 等待消费者线程退出
 
    // 销毁同步原语:释放系统资源,避免内存泄漏
    pthread_mutex_destroy(&g_mutex);          // 销毁互斥锁
    pthread_cond_destroy(&g_cond_prod);       // 销毁生产者条件变量
    pthread_cond_destroy(&g_cond_cons);       // 销毁消费者条件变量
 
    return 0; // 主线程正常退出
}

案例2: 信号量

我就用信号量最经典的**“限流”**场景来举例:只有 3 个窗口的银行,来了 10 个客户办理业务。

在这个例子中,你会看到:

  1. 信号量 充当了“叫号机”和“柜员空闲数”。

  2. 只有 3 个线程能同时运行(办理业务)。

  3. 其他 7 个线程必须阻塞等待,直到有人办完离开。

信号量(Semaphore)-优快云博客https://blog.youkuaiyun.com/Howrun777/article/details/157183697?sharetype=blogdetail&sharerId=157183697&sharerefer=PC&sharesource=Howrun777&spm=1011.2480.3001.8118代码实现

这个代码不需要 pthread_cond,也不需要 while 循环检查,逻辑非常直线条。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h> // 必须引入信号量头文件

#define NUM_WINDOWS 3   // 只有3个柜台窗口
#define NUM_CUSTOMERS 10 // 来了10个客户

sem_t sem_windows; // 定义信号量

// 客户线程函数
void* customer(void* arg) {
    int id = *(int*)arg;
    free(arg); // 释放传进来的内存

    printf("--- 客户 %d 到达银行,正在排队...\n", id);

    // [P操作] 申请资源
    // 信号量 > 0 则减1并进入;
    // 信号量 = 0 则阻塞在这里睡觉
    sem_wait(&sem_windows);

    // --- 临界区(能走到这里说明拿到窗口了) ---
    printf("+++ 客户 %d 抢到了窗口,正在办理业务...\n", id);
    
    sleep(2); // 模拟办理业务耗时 2秒

    printf("<<< 客户 %d 办理完毕,离开窗口\n", id);
    
    // [V操作] 释放资源
    // 信号量 + 1,如果有人在排队,会唤醒其中一个
    sem_post(&sem_windows);

    return NULL;
}

int main() {
    pthread_t tids[NUM_CUSTOMERS];

    // 初始化信号量
    // 第二个参数 0 表示线程间共享
    // 第三个参数 NUM_WINDOWS (3) 是信号量的初始值!表示有3个空位
    sem_init(&sem_windows, 0, NUM_WINDOWS);

    // 创建 10 个客户线程
    for (int i = 0; i < NUM_CUSTOMERS; i++) {
        int* p_id = malloc(sizeof(int)); // 动态分配内存传参
        *p_id = i;
        pthread_create(&tids[i], NULL, customer, p_id);
        
        // 稍微间隔一下让打印好看点,不是必须的
        usleep(100000); 
    }

    // 等待所有线程结束
    for (int i = 0; i < NUM_CUSTOMERS; i++) {
        pthread_join(tids[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&sem_windows);

    return 0;
}

案例3: 环形队列

生产者消费者模型,环形队列 ,信号量, 且单独实现环形队列类

这是一个非常好的练习,能够帮助你理解如何从 面向过程 (C语言) 转向 面向对象 (C++) 的思维方式。在 C++ 中,我们通常会利用 RAII (资源获取即初始化) 技术来管理锁和信号量,利用 模板 (Template) 来让队列支持任意数据类型。

以下是完整的 C++ 实现,包含三个部分:

  1. Semaphore 类:将 POSIX sem_t 封装成 C++ 类(为了 RAII 管理)。

  2. RingQueue 类:线程安全的泛型环形队列。

  3. 主程序:生产者与消费者逻辑。

完整代码 (C++ Standard 11/14/17/20 兼容)

为了保证代码在 Linux/Unix 环境下与之前的 C 代码逻辑一致,底层依然使用 <semaphore.h>,但用 C++ 类进行了封装。

#include <iostream>     // 标准输入输出(cout/endl)
#include <vector>       // 动态数组,用于实现环形队列的缓冲区
#include <thread>       // C++11线程库(线程创建/线程ID获取)
#include <mutex>        // C++11互斥锁(lock_guard)
#include <semaphore.h>  // POSIX信号量(sem_init/sem_wait/sem_post)
#include <unistd.h>     // sleep函数(模拟生产/消费耗时)

// ---------------------------------------------------------
// 1. 信号量封装类 (RAII风格)
// 核心设计:利用C++的构造/析构自动管理信号量生命周期,避免手动销毁导致的资源泄漏
// ---------------------------------------------------------
class Semaphore {
private:
    sem_t _sem;  // POSIX信号量原生对象

public:
    // 构造函数:初始化信号量
    // 参数value:信号量初始值(>=0)
    // sem_init参数说明:
    //   &_sem:要初始化的信号量对象
    //   0:信号量作用域(0=进程内线程共享,非0=进程间共享)
    //   value:信号量初始值(可用资源数)
    Semaphore(int value) {
        sem_init(&_sem, 0, value);
    }

    // 析构函数:销毁信号量(RAII核心:对象销毁时自动释放资源)
    // 避免手动调用sem_destroy遗漏导致的系统资源泄漏
    ~Semaphore() {
        sem_destroy(&_sem);
    }

    // P操作 (Wait/减操作):申请资源,若无可用则阻塞
    // 作用:信号量值-1;若值<0,当前线程阻塞,直到有其他线程调用signal()
    void wait() {
        sem_wait(&_sem);
    }

    // V操作 (Post/Signal/加操作):释放资源,唤醒阻塞线程
    // 作用:信号量值+1;若有线程阻塞在wait(),则唤醒其中一个
    void signal() {
        sem_post(&_sem);
    }
};

// ---------------------------------------------------------
// 2. 线程安全的环形队列类 (模板类)
// 核心设计:
//   - 环形队列:通过head/tail取模实现缓冲区循环复用
//   - 同步机制:信号量(控制空/数据数量)+ 互斥锁(保护临界区)
//   - 线程安全:所有对head/tail/buffer的操作都加锁保护
// ---------------------------------------------------------
template <typename T>  // 模板类:支持任意类型的数据存储
class RingQueue {
private:
    std::vector<T> _buffer; // 环形缓冲区:替代原生数组,自动管理内存(无需手动new/delete)
    int _capacity;          // 队列总容量(缓冲区最大可存储元素数)
    int _head;              // 读索引(消费者使用):指向下一个要取出的元素位置
    int _tail;              // 写索引(生产者使用):指向下一个要写入的元素位置

    // 同步工具:保证多线程访问的安全性和顺序性
    std::mutex _mtx;        // 互斥锁:保护head/tail/_buffer的原子操作(临界区)
    Semaphore _sem_empty;   // 信号量:表示缓冲区的「空闲位置数」(生产者可用资源)
    Semaphore _sem_data;    // 信号量:表示缓冲区的「已存储数据数」(消费者可用资源)

public:
    // 构造函数:初始化环形队列的容量和同步工具
    // 参数cap:队列容量(必须>0)
    RingQueue(int cap) 
        : _capacity(cap),        // 初始化队列总容量
          _buffer(cap),          // 初始化缓冲区大小为cap
          _head(0),              // 读索引初始化为0
          _tail(0),              // 写索引初始化为0
          _sem_empty(cap),       // 初始空闲位置数 = 总容量(队列空)
          _sem_data(0)           // 初始数据数 = 0(队列空)
    {}

    // 禁止拷贝构造和赋值运算符重载
    // 原因:队列包含互斥锁、信号量等不可拷贝的同步对象,拷贝会导致未定义行为
    RingQueue(const RingQueue&) = delete;
    RingQueue& operator=(const RingQueue&) = delete;

    // 入队操作 (生产者调用):将数据写入环形队列
    // 参数data:要写入队列的数据(const& 避免拷贝,提高效率)
    void push(const T& data) {
        // 1. P操作:申请「空闲位置」资源
        //    若队列已满(_sem_empty值=0),生产者线程阻塞,直到消费者取出数据释放空位
        _sem_empty.wait();

        // 2. 加互斥锁:应对多个生产者, 保护临界区(_tail/_buffer的修改)
        //    lock_guard是RAII风格锁:作用域结束时自动解锁,避免手动解锁遗漏导致死锁
        {   // 局部作用域:限制lock_guard的生命周期,解锁时机更精准
            std::lock_guard<std::mutex> lock(_mtx);
            
            // --- 临界区开始:仅允许一个线程执行 ---
            _buffer[_tail] = data;                // 将数据写入当前写索引位置
            _tail = (_tail + 1) % _capacity;      // 写索引后移,取模实现「环形」(到末尾则回到0)
            // --- 临界区结束 ---
        } 
        // 出作用域,lock_guard析构,_mtx自动解锁

        // 3. V操作:释放「数据」资源(通知消费者有新数据可消费)
        //    _sem_data值+1,若有消费者阻塞在pop()的wait(),则唤醒其中一个
        _sem_data.signal();
    }

    // 出队操作 (消费者调用):从环形队列取出数据
    // 参数out_data:输出参数,用于接收取出的数据(指针避免返回值拷贝)
    void pop(T* out_data) {
        // 1. P操作:申请「数据」资源
        //    若队列为空(_sem_data值=0),消费者线程阻塞,直到生产者写入数据
        _sem_data.wait();

        // 2. 加互斥锁:应对多个消费者, 保护临界区(_head/_buffer的读取)
        {
            std::lock_guard<std::mutex> lock(_mtx);

            // --- 临界区开始 ---
            *out_data = _buffer[_head];           // 从当前读索引位置取出数据
            _head = (_head + 1) % _capacity;      // 读索引后移,取模实现环形
            // --- 临界区结束 ---
        }

        // 3. V操作:释放「空闲位置」资源(通知生产者有新空位可写入)
        //    _sem_empty值+1,若有生产者阻塞在push()的wait(),则唤醒其中一个
        _sem_empty.signal();
    }
};

// ---------------------------------------------------------
// 3. 主程序逻辑:生产者-消费者模型测试
// ---------------------------------------------------------

// 全局的环形队列实例:容量为5的整数队列(生产者和消费者共享)
RingQueue<int> g_queue(5);

// 生产者线程函数:无限循环生产数据并写入队列
void producer() {
    int i = 0; // 生产的数据值(从0开始递增)
    while (true) { // 死循环持续生产
        // 打印生产信息:输出线程ID和生产的数据值
        std::cout << "生产者 [" << std::this_thread::get_id() << "] 生产: " << i << std::endl;
        
        // 将数据推入队列:若队列满则自动阻塞,无需手动判断
        g_queue.push(i);
        
        i++; // 下一个要生产的数据值
        sleep(1); // 模拟生产耗时(1秒生产一个数据)
    }
}

// 消费者线程函数:无限循环从队列取出数据并消费
void consumer() {
    while (true) { // 死循环持续消费
        int data; // 存储从队列取出的数据
        
        // 从队列取出数据:若队列为空则自动阻塞,无需手动判断
        g_queue.pop(&data);
        
        // 打印消费信息:输出线程ID和消费的数据值(>>> 区分消费日志)
        std::cout << "  >>> 消费者 [" << std::this_thread::get_id() << "] 消费: " << data << std::endl;
        
        sleep(2); // 模拟消费耗时(2秒消费一个数据,比生产慢,队列会逐渐填满)
    }
}

int main() {
    // 创建生产者线程和消费者线程
    // 线程创建后自动执行对应的线程函数(producer/consumer)
    std::thread t_prod(producer);
    std::thread t_cons(consumer);

    // 等待线程结束:阻塞主线程,直到生产者/消费者线程退出
    // 注:由于线程函数是死循环,此处join()永远不会返回,程序会一直运行
    t_prod.join();
    t_cons.join();

    return 0;
}

注意: 如果是单生产者-单消费者模型, 不需要加锁, 可以只使用信号量完成

C++ 写法的关键点

类封装 (Encapsulation):

  • 使用者不需要手动调用 sem_init 或 sem_destroy,这些都在 Semaphore 和 RingQueue 的构造函数和析构函数中自动完成。

  • 使用者不需要知道内部用的是 sem_wait 还是 pthread_mutex_lock,接口只有简单的 push 和 pop。

RAII 锁管理 (std::lock_guard):

案例4: SPSC 无锁队列实现 (工业级写法)

这才是“不需要锁”的终极形态。我们利用 std::atomic 的 acquire / release 语义来替代锁和信号量。

#include <vector>
#include <atomic>
#include <thread>
#include <iostream>

template <typename T>
class SPSCLockFreeQueue {
private:
    std::vector<T> _buffer;
    int _capacity;
    // 使用 atomic 替代普通的 int,并移除 Mutex 和 Semaphore
    std::atomic<int> _head; 
    std::atomic<int> _tail; 

public:
    SPSCLockFreeQueue(int cap) : _capacity(cap + 1), _buffer(cap + 1), _head(0), _tail(0) {}
    // 注意:实际容量是 cap,多留一个空位用于判断队满(head == (tail + 1) % size)

    // 生产者调用
    bool push(const T& data) {
        int current_tail = _tail.load(std::memory_order_relaxed);
        int next_tail = (current_tail + 1) % _capacity;

        // 检查是否已满:需要读取 _head
        // memory_order_acquire: 保证看到消费者对 _head 的最新修改
        if (next_tail == _head.load(std::memory_order_acquire)) {
            return false; // 队列满
        }

        _buffer[current_tail] = data;

        // 更新 _tail
        // memory_order_release: 保证在此之前的写入(buffer data)对读取 tail 的线程可见
        _tail.store(next_tail, std::memory_order_release);
        return true;
    }

    // 消费者调用
    bool pop(T* out_data) {
        int current_head = _head.load(std::memory_order_relaxed);

        // 检查是否为空:需要读取 _tail
        // memory_order_acquire: 保证看到生产者对 _tail 和 buffer 的最新修改
        if (current_head == _tail.load(std::memory_order_acquire)) {
            return false; // 队列空
        }

        *out_data = _buffer[current_head];

        // 更新 _head
        // memory_order_release: 通知生产者这个位置已经空出来了
        _head.store((current_head + 1) % _capacity, std::memory_order_release);
        return true;
    }
};
  1. 针对你之前的代码:在单生产者-单消费者模式下,可以删掉 mutex。因为 semaphore 的屏障作用已经足够保证安全。你是对的。

  2. 更深层的逻辑:如果你觉得 mutex 慢,那么 semaphore 也很慢。

  3. 最佳实践:真正的 SPSC 优化方案是不使用任何阻塞工具(锁或信号量),而是利用 std::atomic 配合 CPU 缓存一致性协议,实现真正的“零拷贝、零阻塞”。

C++ Builder实战开发案例大全:从项目驱动到工业级应用构建 在桌面应用与工业控制领域,C++ Builder凭借其VCL框架和RAD快速开发能力,成为构建复杂GUI、数据库交互及硬件通信应用的高效工具。其核心原理在于通过可视化组件库与事件驱动模型,实现Windows原生应用的快速开发。技术价值体现在能够显著缩短开发周期,降低多线程同步、数据库连接池等复杂场景的实现门槛。应用场景广泛覆盖串口调试助手、数据采集监控、进销存管理系统等工业与商业软件。本文聚焦于通过实战案例库,系统讲解如何利用C++ Builder进行多线程日志记录器、数据库通用模块等工业级功能开发,其中多 阅读详情

相关推荐

【C++多线程实战】巧用condition_variable构建高效线程同步屏障

本文深入探讨了C++11中condition_variable在多线程编程中的应用,通过实际案例展示了如何构建高效的线程同步屏障。文章详细解析了条件变量与mutex、unique_lock的配合使用,并提供了电商订单处理系统的实战代码示例,帮助开发者避免常见陷阱并优化性能。

weixin_38169786的博客 453

20个有趣的C++实例

return 0;

2302_77692709的博客 4955

【使用C++编写经典的程序示例三一】—— C++ 经典程序范例

它是 C 语言的扩展,支持面向对象的编程范式,同时也保留了 C 语言的高效性和可移植性。在上面的代码中,我们使用了 srand() 函数和 rand() 函数来生成随机数。该程序会随机选择一个数字,然后要求用户输入猜测的数字,如果猜对了就结束游戏。本示例涉及了随机数生成、循环结构、条件语句等多个 C++ 语言特性,是学习 C++ 语言的经典示例之一。程序中还使用了 while 循环来不断读入用户的猜测,并根据猜测的大小给予相应的提示。范围内的随机整数,我们通过对其取模并加一得到1~100之间的随机数。

TechProX的博客 298

c++编程实例

1、#include&lt;iostream&gt; using namespace std; int main() { cout &lt;&lt; "Hello world!" &lt;&lt; "\n"; return 0; }结果Hello world!

a1059682127的博客 3万+

C++多线程通信机制深度解析与实战实现

C++多线程不是简单的API堆砌,而是一种系统性的思维方式。你需要:设计之初就考虑“最小共享”优先使用无锁或原子操作善用工具链(TSan、静态分析)在性能与安全性之间权衡“优秀的并发程序,不是靠锁多,而是靠锁少。” 🎯希望这篇长文能帮你建立起坚实的并发知识体系。下次当你面对“偶发Bug”时,不会再手足无措,而是冷静地说一句:“让我看看是不是数据竞争……”本文还有配套的精品资源,点击获取。

weixin_42578963的博客 314

解锁SPWM电压利用率:三次谐波注入幅值的黄金分割点

本文深入探讨了SPWM电压利用率的提升方法,重点介绍了三次谐波注入技术及其黄金分割点(1/6比例)。通过数学推导和工程实践,揭示了如何通过特定幅值的三次谐波注入将电压利用率从86.6%提升至115%,与SVPWM相当。文章还提供了实验室调试流程和DSP实现代码,帮助工程师优化逆变器设计。

weixin_30729609的博客 915

C++经典程序代码大全

//根据半径计算圆的周长和面积 #include const float PI=3.1416; //声明常量(只读变量)PI为3.1416 float fCir_L(float); //声明自定义函数fCir_L()的原型 float fCir_S(float); //声明自定义函数fCir_S()的原型 //以下是main()函数

zhusg的专栏 18万+

先进半导体材料与器件Chapter3

Chapter3 异质结双极晶体管(HBT) 作者:毛茏玮 / Saint 掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a 微博:https://weibo.com/5458277467/profile?topnav=1&wvr=6&is_all=1 GitHub:github.com/saint-000 知乎:https:/...

一个会写代码的烤鸭 5801

(39)C++ 实例

C++ 实例C++ 实例 - 输出 "Hello, World!"C++ 实例 - 标准输入输出C++ 实例 - 实现两个数相加C++ 实例 - 求商及余数C++ 实例 - 查看 int, float, double 和 char 变量大小C++ 实例 - 交换两个数不使用临时变量,使用异或的方法:C++ 实例 - 判断一个数是奇数还是偶数可以用与运算判断:C++ 实例 - 判断元音/辅音C++ 实例 - 判断三个数中的最大数可以使用临时变量记录最大值也可以使用三元运算符,更为简单参考方法C++ 实例 -

illlllllli的博客 1856

快手did did_gt edid的注册过程

接口 https://gdfp.ksapisrv.com/rest/infra/gdfp/report/kuaishou/android did 是本地生成的16进制 或者 获取的 android_id did_gt 是did生成时间戳 1595073601970 public static final Random f16237a = new Random(System.currentTimeMillis()); public static long m19668a() {  &n

HURUWO的技术博客 1万+

NVIDIA Orin AGX开发环境搭建避坑指南:从Ubuntu 22.04到ROS2完整配置流程

本文详细介绍了NVIDIA Orin AGX开发环境搭建的全流程,从Ubuntu 22.04系统安装到ROS2深度优化,涵盖驱动部署、CUDA环境配置、散热与功耗管理等关键步骤。特别针对Orin AGX的特性提供了实用避坑指南和性能优化技巧,帮助开发者高效完成开发环境配置。

weixin_28340315的博客 450

《C++17并发编程深度解析现代线程安全设计与高效性能优化实战案例》

例如,`std::atomic`的增强原子操作、`[[nodiscard]]`强制结果检查等特性,为开发者提供了更强大的安全护盾,同时`if constexpr`和结构化绑定等新语法简化了复杂并行逻辑的表达,使得开发者能以更清晰的代码结构实现高效的并发任务。- 安全智能指针:`std::shared_ptr`的`atomic`版本可避免引用计数争用,适用于多线程资源管理。- 通过`std::packaged_task`与`std::future`管理异步任务的结果回传。

vuwNYMnn的博客 657

【Python图像处理局部放大】输入图像,选择两处不同的区域进行放大操作,然后将原始图像、处理后的两个区域以及标记合成新图像进行展示

Python图像处理与区域放大连接标记:选择特定区域并对其进行放大操作,然后将原始图像、处理后的两个区域进行标记后的新图像保存到文件中。

qq_35831906的博客 2242

突破C++网络性能瓶颈:cpp-httplib异步模型深度解析与实战指南

你是否还在为C++网络编程中的性能瓶颈发愁?面对高并发场景下的连接阻塞、线程资源耗尽等问题束手无策?本文将带你深入剖析cpp-httplib的异步处理机制,通过实战案例展示如何利用其高效的事件驱动模型提升应用性能,读完你将掌握: - cpp-httplib异步模式的核心工作原理 - 线程池与事件循环的优化配置方案 - 高并发场景下的性能调优实践 - 从零构建支持10k+并发连接的服务端应用 ##...

gitblog_01033的博客 497

LSTM+Transformer混合模型时间序列预测实战教学

LSTM+Transformer混合模型时间序列预测实战教学 毕业设计

8217

Flow Matching03-01:微分方程【微分方程(描述变化规律的方程):包含未知函数和它的导数的方程】【公式解(精确)、数值解(逼近)】

好的,我将从数学角度详细解释Flow Matching,从高中生能理解的基础知识开始,逐步深入到高级概念。

u013250861的博客 218

PCG-CPP进阶技巧:自定义输出函数和状态管理策略

PCG-CPP是一款高效的C++随机数生成库,提供了丰富的随机数生成算法和灵活的使用方式。本文将深入探讨PCG-CPP的进阶技巧,重点介绍如何自定义输出函数以及有效的状态管理策略,帮助开发者更好地利用PCG-CPP库。 ## 自定义输出函数:打造专属随机数格式 🎨 在PCG-CPP中,输出函数决定了随机数的最终呈现形式。通过自定义输出函数,我们可以根据具体需求调整随机数的范围、分布或格式。

gitblog_00031的博客 486

【网络安全】浅谈数据库攻击复现及相关安全优化

4、准备数据库服务器为了安全正式环境应该把数据库单独放一台服务器,只允许让应用服务器 IP 来访问数据库服务器,通过独立两者,就算其中一台发生问题,另一台也是好的,进一步降低了危险性。5、定时备份数据库开发定时备份功能,可以使用 Crontab,或者其他框架,设定周期备份数据,哪怕是数据丢失或被删除也可以快速恢复。

2401_88545587的博客 221

C++多线程简单版(C++11 及以上)

C++11 提供<thread>库实现跨平台多线程,核心类是;多线程的核心问题是数据竞争,需用std::mutex(配合)保护共享资源;join()等待线程完成,detach()分离线程(慎用);多线程编程的关键是“保护共享资源,避免竞态条件”。

写点没用的。(debug)? log : dog 723

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++并发编程实战指南

C++并发编程实战指南》是一本深受开发者欢迎的书籍,旨在帮助读者深入理解和掌握C++并发编程的核心技术和实践方法。在《C++并发编程实战指南》中,作者首先介绍了并发编程的基本概念,包括线程、锁、同步、异步等。《C++并发编程实战指南》通过一个详细的线程池实现案例,展示了如何创建和管理线程池,以及如何将任务分配给线程池中的线程执行。并发编程在提高程序性能的同时,也可能引入新的性能问题和调试困难。在掌握了并发编程基础后,《C++并发编程实战指南》进一步介绍了高级并发技术,包括原子操作、内存模型、条件变量等。

2501_92486623的博客 473

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

c++线程池

一个简单的线程池模型实现 http://www.codeweblog.com/一个简单的线程池模型实现/#0-tsina-1-45851-397232819ff9a47a7b7e80a40613cfe1QT 线程池 + TCP 实战笔记 线程池的简单实现 http://www.linuxidc.com/Linux/2012-10/71629.htm#0-tsina-1-719-39723281

xcw_1987的博客 298

突破性能瓶颈:llama.cpp性能测试工具全解析与调优指南

你是否还在为本地大模型运行卡顿而烦恼?是否想知道如何充分发挥硬件潜力?本文将深入解析llama.cpp性能测试工具的工作原理,通过实战案例带你掌握性能优化的关键技巧,让你的本地LLM运行效率提升300%。 读完本文你将获得: - 性能测试工具的核心功能与使用方法 - 关键参数调优的实战技巧 - 多场景下的性能对比分析 - 常见性能问题的诊断与解决 ## 工具概述与架构解析 llama.cpp...

gitblog_00283的博客 951

C++ 并发编程实战第二版:深入理解C++并发编程的艺术

C++ 并发编程实战第二版:深入理解C++并发编程的艺术 【下载地址】C并发编程实战第二版 《C++ 并发编程实战 第二版》是一本全面解析 C++ 并发编程的权威指南,深入探讨了 std::thread、std::mutex、std::async 等核心工具的使用,以及原子操作和内存模型的复杂机制。本书从基础概念到高级技...

gitblog_06740的博客 369

第26章-C++中级实战案例(20个)

本章提供20个精选的C++中级实战案例,涵盖面向对象编程、STL容器和算法、文件操作、异常处理、模板编程、智能指针等进阶知识点。每个案例注重实际应用场景,帮助学习者从初级水平过渡到中高级,掌握更复杂的编程技巧和设计模式。

qq_31762031的博客 1023

JavaScript与C++混合编程:JSBrowser中NativeListener组件的深度解析与实战指南

在现代Web开发领域,**JavaScript与C++混合编程**技术为开发者提供了强大的能力,能够结合两者的优势创造出高性能的桌面应用。JSBrowser项目正是这一技术的杰出代表,它作为一个完全用JavaScript构建的Windows应用浏览器,通过**NativeListener组件**实现了JavaScript与C++的无缝协作。本文将深入解析JSBrowser中NativeListen

gitblog_00406的博客 936

C++静态成员函数访问权限:从封装原理到8个实战案例解析

在C++面向对象编程中,封装是核心概念之一,它通过访问权限控制(public、private、protected)来隐藏实现细节,仅暴露必要接口。静态成员函数作为绑定在类本身而非对象实例的特殊函数,其访问权限设计直接影响代码的健壮性和可维护性。从技术原理看,静态函数没有this指针,因此无法直接访问非静态成员,但其访问静态成员时仍需遵循权限规则。这一特性在工程实践中具有重要价值,例如在单例模式中,通过private静态函数隐藏初始化逻辑;在工厂模式中,利用public静态函数提供统一创建接口;在继承体系中,

weixin_33826609的博客 277
上一篇: 信号量(Semaphore)
下一篇: Linux_C++_日志实例
Howrun777
博客等级 码龄1年 133粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值