C++开发基础——原子操作与多线程编程

c++多线程(5)------原子操作 C++11 引入了 <atomic> 头文件和 std::atomic<T> 模板类,为多线程编程提供了无锁(lock-free)的原子操作支持。原子操作是并发编程中的基础构建块,用于在不使用互斥锁(mutex)的情况下实现线程安全的数据访问。 阅读详情

一,线程的创建与终止

线程是CPU最小的执行和调度单位。多个线程共享进程的资源。

创建线程比创建进程更快,开销更小。

创建线程的方法:pthread_create、std::thread。

pthread_create:传入的线程函数只有一个参数。

std::thread:传入的线程函数可以有任意数量的参数。

因为,thread类的构造函数是一个可变参数模板,可接收任意数目的参数,其中第一个参数是线程对应的函数名称。

std::thread调用以后返回一个线程类,每创建一个线程类,就会在系统中启动一个线程,并利用这个线程类来管理线程。

线程类可以被移动,但是不可以被复制,可以调用move()来改变线程的所有权。

线程的标识符是线程id,线程类可以调用this_thread::get_id()来获得当前线程的id。

创建线程以后,可以调用join()或者detach()来等待线程结束,join()会等启动的线程运行结束以后再继续执行当前代码,detach()会直接往后继续执行当前代码,而不需要等待启动的线程运行结束。如果调用detach()分离线程,该线程结束后,线程资源会自动被系统回收。

std::thread常用的创建线程类的方式有:

通过函数指针创建线程

通过函数对象创建线程

通过lambda表达式创建线程

通过成员函数创建线程

1.通过函数指针创建线程

代码样例:

函数

void counter(int id, int numIterations)
{
    for(int i=0; i<numIterations; ++i){
        cout << "Counter " << id << " has value " << i << endl;
    }
}

利用函数创建线程:

thread t1(counter, 1, 6);
thread t2(counter, 2, 4);
t1.join();
t2.join();

注意,线程中的函数,比如counter(),在创建线程的时候,默认的传参方式是值拷贝,比如id,numIterations会被拷贝以后再传递到线程空间中。

2.通过函数对象创建线程

代码样例:

函数对象Counter:

class Counter
{
    public:
    Counter(int id, int numIterations)
    :mId(id), mNumIterations(numIterations)
    {

    }

    //重载运算符operator()
    void operator()() const
    {
        for(int i=0; i < mNumIterations; ++i){
            cout << "Counter " << mId << " has value " << i << endl;
        }
    }

    private:
        int mId;
        int mNumIterations;
};

利用函数对象创建线程:

方法1:通过构造函数创建Counter类的一个实例,将实例传递给thread类

thread t1{Counter{1, 4}};

方法2:创建Counter类的一个实例c,将实例传递给thread类

Counter c(2, 5);
thread t2(c);

完整代码实现: 

#include <thread>
#include <iostream>

using namespace std;

class Counter
{
    public:
    Counter(int id, int numIterations)
    :mId(id), mNumIterations(numIterations)
    {

    }

    //重载运算符operator()
    void operator()() const
    {
        for(int i=0; i < mNumIterations; ++i){
            cout << "Counter " << mId << " has value " << i << endl;
        }
    }

    private:
        int mId;
        int mNumIterations;
};

int main(){
    thread t1{Counter{1, 4}};
    Counter c(2, 5);
    thread t2(c);

    t1.join();
    t2.join();

    cout << "Main thread end." << endl;
    return 0;
}

运行结果:

Counter 1 has value 0
Counter 1 has value 1
Counter 1 has value 2
Counter 1 has value 3
Counter 2 has value 0
Counter 2 has value 1
Counter 2 has value 2
Counter 2 has value 3
Counter 2 has value 4
Main thread end.

3.通过lambda表达式创建线程

代码样例:

#include <thread>
#include <iostream>

using namespace std;

int main(){
    int id = 1;
    int numIterations = 5;
    thread t1(
        [id, numIterations]{
            for(int i=0; i<numIterations; ++i){
                cout << "Counter " << id << " has value " << i << endl;
            }
        }
    );

    t1.join();
    return 0;
}

运行结果:

Counter 1 has value 0
Counter 1 has value 1
Counter 1 has value 2
Counter 1 has value 3
Counter 1 has value 4

4.通过成员函数创建线程

代码样例:

在线程中指定要执行该类的哪个成员函数。

#include <thread>
#include <iostream>

using namespace std;

class Request
{
    public:
        Request(int id): mId(id){ }

        void process()
        {
            cout << "Processing request." << mId << endl;
        }
    private:
        int mId;
};

int main(){
    Request req_obj(100);
    thread t{ &Request::process, &req_obj };

    t.join();
    return 0;
}

运行结果:

Processing request.100

我们也可用采用RAII写法,封装一个新的线程类,在线程类析构的时候自动调用join()来等待线程执行结束,写法如下:

class RaiiThread {
private:
    std::thread& t;
public:
    RaiiThread(std::thread& _t ) : t(_t) {}

    ~RaiiThread() {
        if(t.joinable())
            t.join();
    }        

    //线程类不能被拷贝
    RaiiThread(const RaiiThread &)= delete;
    RaiiThread& operator=(const RaiiThread &)= delete ;
};

5.线程的终止

线程终止的方式有:

1.线程函数运行完返回,该子线程终止。

2.同一进程中的其他线程调用pthread_cancel()取消该线程,该子线程终止。

3.线程函数中调用pthread_exit()主动退出,该子线程终止。

4.主线程(main函数中)退出,所有子线程全部被终止。

5.子线程调用exit()函数,整个进程被终止。

二,thread_local变量

thread_local关键字可以实现线程的本地存储。

thread_local变量在多线程中只初始化一次,而且每个线程都有这个变量的独立副本, 每个线程都可以独立访问和修改自己的变量副本,而不会干扰其他线程。

thread_local变量的生命周期从初始化时开始,到线程运行完毕时结束。

int m;  //所有线程共享m
thread_local int n; //每个线程都有自己的n副本

代码样例:

#include <iostream>
#include <thread>
using namespace std;
void thread_func()
{
       thread_local int stls_variable = 0;
       stls_variable += 1;
       cout << "Thread ID: " << this_thread::get_id()
              << ", Variable: " << stls_variable
              << endl;
}
int main()
{
       thread t1(thread_func);
       thread t2(thread_func);
       t1.join();
       t2.join();
       return 0;
}

运行结果:

Thread ID: 16312, Variable: 1
Thread ID: 14848, Variable: 1

三,原子类型与原子操作

1.原子操作与数据安全

    对于一个变量,编译器首先将值从内存加载到寄存器中,在寄存器中进行处理,然后再把结果保存回内存。由于多个线程共享进程中的内存空间,因此,这段内存可以被多个线程同时访问,导致数据争用。原子操作可以解决数据争用问题,保证数据安全。

    如果对一个共享内存资源的操作是原子操作,当多个线程访问该共享资源时,在同一时刻,有且仅有一个线程可以对这个资源进行操作。

实现原子操作的方式:

1,使用互斥锁等同步机制

2,使用原子类型

2.常见的原子类型

图源自《深入理解C++11》

除了使用内置类型,开发者可以通过atomic类模板来自定义原子类型。

例如,定义一个T类型的原子类型变量t

std::atomic<T> t;

3.代码样例

使用原子类型之前的多线程代码:

#include <atomic>
using namespace std;

void increment(int& counter)
{
    for (int i = 0; i < 100; ++i){
        ++counter;
        this_thread::sleep_for(1ms);
    }
}

int main()
{
    int counter = 0;
    vector<thread> threads;
    for(int i = 0; i < 10; ++i){
        threads.push_back(thread{ increment, ref(counter) });
    }
    for (auto& t : threads){
        t.join();
    }
    cout << "Result = " << counter << endl;
}

使用原子类型之后的多线程代码:

#include <atomic>
using namespace std;

void increment(atomic<int>& counter)
{
    for(int i=0; i<100; ++i){
        ++counter;
        this_thread::sleep_for(1ms);
    }
}

int main()
{
    atomic<int> counter(0);
    vector<thread> threads;
    for(int i = 0; i < 10; ++i){
        threads.push_back(thread{increment, ref(counter)});
    }
    for (auto& t : threads){
        t.join();
    }
    cout << "Result = " << counter << endl;
}

原子类型可以省去在线程的函数中进行加锁和解锁的操作,下面两段代码实现的效果一样:

Demo1:

#include <thread>
#include <iostream>
using namespace std;

static long total = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void* func(void *){
    long i;
    for (i = 0; i < 999; i++)
    {
        pthread_mutex_lock(&m);
        total += 1;
        pthread_mutex_unlock(&m);
    }
}

int main(){
    pthread_t thread1, thread2;
    if (pthread_create(&thread1, NULL, &func, NULL)){
        throw;
    }
    if (pthread_create(&thread2, NULL, &func, NULL)){
        throw;
    }
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    cout << total << endl;
    return 0;
}

运行结果:

1998

Demo2:

#include <thread>
#include <iostream>
#include <atomic>
using namespace std;

atomic_long total {0};  //原子数据类型

void* func(void *){
    long i;
    for (i = 0; i < 999; i++)
    {
        total += 1;
    }
}

int main(){
    pthread_t thread1, thread2;
    if (pthread_create(&thread1, NULL, &func, NULL)){
        throw;
    }
    if (pthread_create(&thread2, NULL, &func, NULL)){
        throw;
    }
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    cout << total << endl;
    return 0;
}

运行结果:

1998

四,互斥体与锁

    对于数组类型或者布尔类型等简单的数据类型可以使用原子操作来同步,如果当数据类型变得很复杂的时候,需要采用显式的同步机制来保证线程之间的同步,常用的同步机制有互斥体类和锁类。

    锁类的对象可以用来管理互斥体类的对象,比如unique_lock对象可以管理mutex对象。

    互斥体的主要操作是加锁(lock)和解锁(unlock)。

    互斥体还分定时互斥体和非定时互斥体。

1.非定时互斥体

头文件 :<mutex>

互斥体名:std::mutex、std::recursive_mutex

头文件:<shared_mutex>

互斥体名:std::shared_mutex

std::mutex互斥体的常用方法:

lock():调用该方法的线程将尝试获取锁,获取不到锁就会一直阻塞。

try_lock():调用该方法的线程将尝试获取锁,获取不到锁就会立即返回,获得锁时返回true,未获得锁时返回false。

unlock():释放由该线程持有的锁。

shared_mutex类功能和读写锁类似,写文件的时候加锁,然后独占所有权,读文件的时候加锁,但是会和其他线程共享所有权。

shared_mutex类除了支持lock()、try_lock()、unlock()等方法获取和释放锁,还支持lock_shared()、try_lock_shared()、unlock_shared()等方法获取和释放共享所有权。

注意:已经获取到锁的线程不能再次调用lock()和try_lock(),否则可能导致死锁。

2.定时互斥体

头文件:<mutex>

互斥体名:std::timed_mutex                  

头文件:<shared_mutex>

互斥体名:std::shared_timed_mutex

shared_timed_mutex类除了支持lock()、try_lock()、unlock()等方法获取和释放锁,还支持lock_shared()、try_lock_shared()、unlock_shared()等方法获取和释放共享所有权。

std::timed_mutex定时互斥体还支持以下方法: 

try_lock_for():调用该方法的线程在给定时间间隔内尝试获取锁,在超时之前获取锁失败,返回false,在超时之前获取锁成功,返回true。

try_lock_until():调用该方法的线程在到达指定时间点之前尝试获取锁,在超时之前获取锁失败,返回false,在超时之前获取锁成功,返回true。

3.互斥锁

锁类是RAII写法,不需要手动释放和获取锁,比如lock_guard锁的构造函数里调用了锁的lock成员函数,析构函数里调用了锁的unlock成员函数。

因此,在生命周期结束或离开作用域时,锁类的析构函数会自动释放所关联的互斥体等资源。不需要手动调用unlock()方法,这样可以避免使用锁的时候出现问题,还可以防止死锁的发生。

锁类在标准库中都是模板类,用来生成锁的对象。

C++中常用的锁类:

头文件:<mutex>

常见的锁类:

std::lock_guard

std::unique_lock

std::scoped_lock 

std::scoped_lock与std::lock_guard类似,它接收数量可变的互斥体,可以获取多个锁。           std::lock_guard比较轻量级,执行速度比std::unique_lock更快,但是std::unique_lock用法更灵活。std::lock_guard创建对象即加锁,不能显式的调用lock()和unlock(),而std::unique_lock可以在任意时候调用它们。

std::unique_lock类包含以下方法:

lock():加锁。

unlock():解锁。

try_lock():尝试获取锁,获取失败返回false,获取成功返回true。

try_lock_for():尝试在指定时间段内获取锁,获取失败返回false,获取成功返回true。

try_lock_until():尝试在指定时间点之前获取锁,获取失败返回false,获取成功返回true。

release():释放所有权。

4.代码样例

#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
int main()
{
    int counter = 0;
    std::mutex counter_mutex;
    std::vector<std::thread> threads;
    auto worker_task = [&](int id){
        std::unique_lock<std::mutex> lock(counter_mutex);
        ++counter;
        std::cout << id << ", initial counter: " << counter << '\n';
        lock.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lock.lock();
        ++counter;
        std::cout << id << ", final counter: " << counter << '\n';
    };
    for (int i = 0; i < 5; ++i)
    {
        threads.emplace_back(worker_task, i);
    }
    for (auto& thread : threads)
    {
        thread.join();
    }
    return 0;  
}

运行结果:

0, initial counter: 1
1, initial counter: 2
2, initial counter: 3
3, initial counter: 4
4, initial counter: 5
0, final counter: 6
3, final counter: 7
1, final counter: 8
2, final counter: 9
4, final counter: 10

五,条件变量

条件变量的使用在一定程度上可以避免线程的死锁。

条件变量可以让线程一直阻塞,直到某个条件成立,这个条件可以是另一个线程完成了某操作或者系统时间达到了指定时间。

条件变量允许显式的线程间通信。

条件变量所在的头文件:<condition_variable>

常用的两个条件变量:

std::condition_variable:只能等待unique_lock<mutex>上的条件变量。std::condition_variable_any:可等待任何对象的条件变量,包括自定义的锁类型,自定义的锁类应提供lock()和unlock()方法。

两种条件变量都支持以下常用的方法:

notify_one():唤醒等待这个条件变量的线程之一。

notify_all():唤醒等待这个条件变量的所有线程。

wait():阻塞当前线程,直到条件变量被唤醒。

wait_for():阻塞当前线程,直到条件变量被唤醒,或到达指定时长。

wait_until():阻塞当前线程,直到条件变量被唤醒,或到达指定时间点。

六,多线程代码实战——线程安全的队列

1.具体设计

1.使用互斥锁来保护共享资源,这里的共享资源是队列。

2.互斥锁在push或者pop队列的时候加锁,在执行完毕后解锁。

3.使用条件变量来等待队列的更改。

4.当数据元素被添加到队列中时,条件变量会notify正在等待的线程,等待队列被更改的线程被唤醒并开始操作。

5.线程从队列中删除数据元素时,会先检查队列是否为空,如果为空,它会等待条件变量,直到有新元素被添加到队列中。

2.代码实现

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>

template <typename T>
class TSQueue {
private:
    std::queue<T> m_queue;

    // mutex for thread synchronization
    std::mutex m_mutex;

    // Condition variable for signaling
    std::condition_variable m_cond;

public:
    void push(T item)
    {
        // acquire lock
        std::unique_lock<std::mutex> lock(m_mutex);

        m_queue.push(item);

        // Notify one thread that is waiting
        m_cond.notify_one();
    }

    T pop()
    {
        // acquire lock
        std::unique_lock<std::mutex> lock(m_mutex);

        // wait until queue is not empty
        m_cond.wait(lock,
            [this]() { return !m_queue.empty(); });

        T item = m_queue.front();
        m_queue.pop();

        return item;
    }
};

int main()
{
    TSQueue<int> q;

    // Push some data
    q.push(30);
    q.push(40);
    q.push(50);

    // Pop some data
    std::cout << q.pop() << std::endl;
    std::cout << q.pop() << std::endl;
    std::cout << q.pop() << std::endl;

    return 0;
}

运行结果:

30
40
50

七,参考阅读

《C++高级编程》

《深入理解C++11》

《C++新经典》

《C++并发编程实战》

https://www.apiref.com/cpp-zh/cpp/thread/

Implement thread-safe queue in C++_GeeksforGeeks

std::unique_lock<Mutex>::lock_cppreference.com

荔枝派Lichee Nano全志F1C100s烧录避坑指南:从Fel模式到SPI Flash完整流程 本文详细介绍了荔枝派Lichee Nano基于全志F1C100s芯片的SPI Flash烧录完整流程,从FEL模式进入技巧到定制化sunxi-tools编译,再到分区策略与实战烧录步骤。针对开发者常见的烧录程序问题提供了专业解决方案,帮助用户高效完成嵌入式系统部署。 阅读详情

相关推荐

使用moveit!控制真实机械臂(5)——编写真实机械臂节点中的action服务程序

上一篇文章中,我们简要介绍了ROS中action的基本知识,为了控制真实机械臂,我们已经修改了moveit配置文件,使得moveti启动后具备一个control_msgs::FollowJointTrajectoryAction类型的action客户端,接下来,我们完成该类型action的另一半,编写C++程序来实现action的服务端。由于底层机器人控制程序一般差别都很大,这里展示的只是编程要点...

爱学习的草莓熊 1万+

线程安全之原子操作

被final修饰的变量会返回正确的构造版本,在一定程度上(构造函数)可以解决内存可见性问题,如下代码: package 多线程; import org.junit.Test; /** * @Author: cxl * @Date: 2020/3/3 17:05 * @Version 1.0 */ public class Test01 { final int x; ...

qq_40757662的博客 290

vasp-自旋轨道耦合(SOC)计算步骤

在VASP中执行自旋轨道耦合(SOC)计算,具体的计算步骤如下: 结构优化获取CONTCAR文件 自洽计算(collinear normal VASP calculations)获取IBZKPT,CHGCAR和WAVECAR文件。 SCF+SOC计算,在此步骤中,将步骤2中的IBZKPT复制为KPOINTS,以便两个步骤具有相同的k网格,因此可以读取步骤2中的CHGCAR和WAVECAR文件。 能带结构计算,在此步骤中,将KPOINTS改为高对称点,读取步骤3中的CHGCAR和WAVECAR文件。

懒散的鱼与消失的猫 3万+

C++多线程——原子操作atomic

原子操作 示例 原子操作 是个不可分割的操作。 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的; 它要么就是做了,要么就是没做,只有这两种可能。 不使用原子操作: #include <iostream> #include <thread> #include <atomic> using namespace std; long num = ...

princeteng's blogs 3499

PyMiMi实战指南:midas_api配置与连接测试详解

本文详细介绍了PyMiMi库中midas_api的配置与连接测试全流程。从环境准备、API密钥获取,到核心的url_cfg配置函数使用,再到通过test_url进行连接验证,提供了清晰的步骤和代码示例。文章重点解析了配置原理、常见错误排查方法(如401错误、连接超时),并强调了API密钥的安全性管理,帮助用户稳固建立Python与Midas Civil NX之间的自动化通信桥梁。

weixin_29044713的博客 696

098、C3k2_Ghost:用 GhostConv 替代 C3k2 内标准卷积的轻量化改造代码

本文介绍了用GhostConv轻量化改造YOLOv11中C3k2模块的实践。作者通过线上部署案例引出问题,详细解析了GhostConv的核心实现逻辑,指出直接替换标准卷积会导致的两个关键问题:通道数不匹配和kernel_size冲突。文章提供了完整的C3k2_Ghost实现代码,包含注意事项和调试技巧。消融实验显示,该方法在小模型上可减少27%-28%参数量、34%-35%FLOPs,仅损失0.8mAP。作者总结了适用场景:小模型效果显著,大模型需谨慎;检测小目标任务不推荐;训练时需调整学习率。最后强调sh

sundong_81的博客 62

pthread和std::thread对比

std::thread是C++11接口,pthread是C++98接口且只支持Linux。 示例: pthread_create(&thread, &attr, f, static_cast<void *>(&args)); // 其中f是函数,args是所有参数打包成的结构体。因为pthread_create的第四个参数类型是void*,所以需要强制转型...

grandgrandpa的博客 6755

某物data魔改与变种算法还原(含加解密Py纯算)

某物data加解密、设备指纹魔改、变异、自定义加密分析与纯算还原

吴秋霖的博客 1281

C++`中的原子操作和原子类型

5.2 C++中的原子操作和原子类型 原子操作 是个不可分割的操作。 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的; 它要么就是做了,要么就是没做,只有这两种可能。 如果从对象读取值的加载操作是 原子 的,而且对这个对象的所有修改操作也是 原子 的, 那么加载操作得到的值要么是对象的初始值,要么是某次修改操作存入的值。 另一方面,非原子操作可能会被另一个线程观察到只完成一半。 如果这个操作是一个存储操作,那么其他线程看到的值,可能既不是存储前的值,也不是存储的值,而是别的什么值。 如果这

weixin_42252757的博客 7198

【华为OD技术面试手撕真题】25、验证IP地址 | 手撕真题+思路参考+代码解析(C & C++ & Java & Python & JS)

验证IP地址 华为od机试真题,华为OD技术二面,华为od机考,华为od手撕真题,华为od技术二面,华为od机试,华为OD机试的高频手撕代码题,华为od八股文

KJ.JK 4043

仿真学习系列(四十九):Sigrity仿真之电容库制作

在高速电路设计中,电源完整性(PI)是确保系统稳定、可靠运行的关键因素。随着电子产品对性能的要求不断提升,PDN(电源分配网络)的设计与优化变得尤为重要。为了确保电源网络在高速工作状态下不会引发电压波动和信号干扰,我们需要在设计中精确地选择电容器进行优化,而电容库的制作则是这一过程的核心。 OptimizePI作为一个强大的电源完整性优化工具,能够帮助设计师根据不同的目标,批量进行PDN仿真,以得出最佳电容选择。

案例文章,高速信号 224

c++开发基础之保障多线程编程中的原子操作InterlockedIncrement和InterlockedDecrement用法详解

在多线程编程中,确保对共享变量进行原子操作是至关重要的。当多个线程同时访问和修改同一共享资源时,如果没有合适的同步机制,可能会导致数据竞争、内存一致性问题,甚至造成程序崩溃。为了解决这个问题,C++提供了一组原子操作函数,其中包括InterlockedIncrement和InterlockedDecrement。本文将深入探讨这两个函数的用法,以及它们在多线程环境中的重要性。

dotnet研习社 1639

Python爬虫实战:爬取小红书数据做爆款分析,我破解了签名加密+移动端反爬(附完整代码)

爬取小红书数据的核心,不是“简单的HTTP请求”,而是“理解移动端接口的加密逻辑和反爬规则”——从x-s/x-t签名破解到移动端UA伪装,再到行为模拟,每一步都是对移动端爬虫的深度理解。这套方案的价值在于,不仅能稳定抓取小红书数据,还能从数据中拆解出有价值的爆款特征,真正把“数据”变成“洞察”。对程序员来说,小红书爬虫不仅是技术练手,更是了解新媒体平台数据逻辑的窗口。希望这篇分享能帮到做新媒体分析或爬虫进阶的小伙伴,也欢迎在评论区交流小红书反爬和爆款分析的更多技巧!

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2058

C++17并发编程实战:多线程与原子操作的最佳实践

原子操作是一类不可分割的操作,在任何线程中执行时,要么完全完成,要么尚未开始。这种特性确保了多线程环境下数据的完整性。读取操作:要么获取初始值,要么获取修改后的值。写入操作:其他线程不会看到部分写入的结果。C++17为并发编程提供了强大的工具,尤其是原子操作的改进使得编写高效、安全的多线程代码更加容易。通过合理使用原子类型、内存顺序和同步机制,开发者可以显著提升程序的性能和可靠性。然而,仍需注意避免数据竞争和性能陷阱,并结合调试工具确保代码的正确性。

Momo__omoM的博客 1225

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

P多线程编程基础.cpp

本文介绍了C++多线程编程的核心技术,包括线程创建与管理、参数传递、同步机制等关键内容。通过具体代码示例,展示了如何使用std::thread创建线程、通过互斥锁(mutex)解决数据竞争、利用条件变量实现线程协作,以及构建简单线程池的方法。文章还探讨了原子操作和线程局部存储(TLS)等进阶技术,并提供了并行计算的实际案例。最后强调了多线程编程中的线程安全、死锁预防和性能优化等注意事项,为开发高效并发程序提供了实用指导。

m0_66709139的博客 970

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

精通 C++ 多线程(一)

多线程应用程序在单处理器环境中执行多个线程,以实现。本书充满了实际示例,将帮助您成为在 C++中编写健壮的并发和并行应用程序的专家。在本书中,您将深入了解多线程和并发的基础知识,并了解如何实现它们。在此过程中,您将探索原子操作以优化代码性能,并将并发应用于分布式计算和 GPGPU 处理。在本章中,我们讨论了使用本机线程 API 在 C++中实现多线程应用程序的基础知识。我们看了如何让多个线程并行执行任务,并探讨了如何在多线程应用程序中正确使用 STL 中的随机数 API。

龙哥盟 714

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

C++多线程并发编程入门(目录)

在 Windows 环境上,我们使用 Visual Studio 2022 来开发 STL版本的代码(std::thread),以及 Windows 平台的代码(CreateThread)。Linux 环境的代码开发调试,我们会在Windows上另外搭建开发环境来实现。由于我们的代码有些只能运行在 Windows 环境,有些只能运行在Linux 环境,所以我们准备了两套开发环境。我提供两个开发Linux 环境代码的开发环境搭建教程,大家自己任选其中的一个。项目3 Qt+ffmpeg拉流播放器(期待ing)

C++ 爱好者 make_it_simple888 1202

C++ 多线程编程

本文介绍了C++多线程编程的核心概念和常用技术。主要内容包括:1. 基本头文件及线程创建:使用std::thread创建线程,join/detach方法的使用;2. 线程同步机制:互斥锁(std::mutex)、锁保护类(std::lock_guard, std::unique_lock)的使用;3. 原子操作(std::atomic)实现无锁编程;4. 条件变量(std::condition_variable)实现线程间协调;5. 高级异步操作(std::async, std::future, std::

如梦人身 1300

C++多线程编程:从入门到精通,构建高性能并发应用,非常详细,强烈建议收藏!!!

C++多线程编程

qq_44630255的博客 1160

C++多线程编程深入解析

C++多线程编程是一项复杂而强大的技术,能够有效提高程序的性能和响应速度。然而,它也带来了一系列挑战,需要开发者深入理解和掌握。本文从多线程编程的基础、数据共享与保护、线程间的通信与同步、挑战与优化等方面进行了深入解析,希望对读者在C++多线程编程方面的学习和实践有所帮助。未来,随着硬件的发展和多核处理器的普及,多线程编程将变得更加重要。开发者需要不断学习和探索新的多线程编程技术和工具,以提高程序的并行性能和效率。

maohoubaji的博客 320

C++内存模型和原子类型操作

c++ memory order 内存序

D_Guco的专栏 1217

c++11并发与多线程

c++11并发与多线程0.引言一.基本概念和实现1.1.并发、进程、线程的基本概念1.1.1 并发1.1.2 可执行程序1.1.3 进程1.1.4 线程1.1.5 学习心得1.2.并发的实现方法1.2.1 多进程并发1.2.2 多线程并发1.2.3.总结1.3.C++11新标准线程库二.线程启动、结束,创建线程多法、join,detach2.1.范例演示线程运行的开始2.2.其他创建线程的方法三.线程传参详解,detach()大坑,成员函数做线程函数3.1.传递临时对象作为线程参数3.2.临时对象作为线程.

fb_941219的博客 1733

多线程Cpp

文章目录0.基本概念1.进程2.线程3.并发3.1 多进程并发3.2 多线程并发4.jion()5.detach()6.jionable()7.注意8.粒度1.线程休眠2.启动线程3.传递参数3.1传递临时对象作为线程参数4.线程id5.传递类对象、智能指针、类成员函数和类对象作为线程参数5.1 传递类对象5.2 传递智能指针5.3 类成员函数5.3 类对象6.数据共享问题:6.1 只读数据6.2 读写数据7.互斥量7.1 互斥量的使用7.2 std::lock_guard()8.死锁8.1概念8.2 死锁

Destiny_的博客 3775

C++多线程编程入门实战

本文介绍了C++多线程编程的基础知识和实践方法。首先源代码展示了单线程与多线程的性能对比...这篇文章对C++多线程编程进行了系统介绍,从基础概念到实际应用,包括单线程与多线程对比、数据竞争与互锁解决方案、何时使用原子操作等核心scape,为初学者提供了清晰_BUILD_的完整路径。

hour_go的博客 618

C++多线程并发编程

同步原语包括std::mutex、std::recursive_mutex(可重入锁)及std::timed_mutex(带超时功能)。原子操作(std::atomic)提供无锁编程支持,适用于高性能场景,如计数器或标志位操作,确保操作的原子性而无须显式锁机制。并行算法(C++17)如std::for_each与执行策略(std::execution::par)简化了数据并行化。实践中,应优先使用RAII模式管理资源(如std::lock_guard),并结合设计模式(如生产者-消费者)构建健壮系统。

u010682093的博客 365

C++内存模型与多线程编程从基础到实战

C++内存模型和多线程编程要求谨慎处理共享状态。优先使用原子操作代替锁 when possible,并选择合适的内存顺序。始终使用RAII管理锁资源,避免死锁。测试并发代码 under heavy load 以揭露潜在问题。掌握这些基础到实战的知识,能够构建出高效、可靠的并发应用程序。

yanglo的博客 305
上一篇: C++开发基础——拷贝构造/移动构造/委托构造
下一篇: C++开发基础——IO操作与文件流
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员与背包客_CoderZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值