c++使用的比较少,不太熟悉

在 C++ 中,可以使用标准库(C++11 引入的 std::thread)来创建和管理线程。以下是创建线程的几种常用方法:


1. 使用普通函数作为线程入口

#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    // 创建线程
    std::thread t(threadFunction);

    // 等待线程完成
    t.join();

    std::cout << "Thread finished." << std::endl;
    return 0;
}
  • 解释

    • std::thread t(threadFunction); 创建一个新线程,并指定 threadFunction 为线程入口函数。

    • t.join(); 等待线程执行完成,主线程会阻塞直到子线程结束。


2. 使用 lambda 表达式

#include <iostream>
#include <thread>

int main() {
    // 使用 lambda 表达式创建线程
    std::thread t([]() {
        std::cout << "Hello from lambda thread!" << std::endl;
    });

    t.join();

    std::cout << "Lambda thread finished." << std::endl;
    return 0;
}
  • 解释

    • Lambda 表达式非常适合简化代码,尤其是在小型任务中。


3. 使用类的成员函数

如果线程的入口是一个类的成员函数,可以使用以下方式:

3.1 普通成员函数

#include <iostream>
#include <thread>

class MyClass {
public:
    void threadFunction() {
        std::cout << "Hello from member function thread!" << std::endl;
    }
};

int main() {
    MyClass obj;

    // 使用 std::bind 或 lambda 捕获 this 指针
    std::thread t(&MyClass::threadFunction, &obj);

    t.join();

    std::cout << "Member function thread finished." << std::endl;
    return 0;
}
  • 解释

    • &MyClass::threadFunction 是成员函数指针。

    • &obj 是对象指针,用于调用该成员函数。

3.2 静态成员函数

#include <iostream>
#include <thread>

class MyClass {
public:
    static void threadFunction() {
        std::cout << "Hello from static member function thread!" << std::endl;
    }
};

int main() {
    std::thread t(&MyClass::threadFunction);

    t.join();

    std::cout << "Static member function thread finished." << std::endl;
    return 0;
}
  • 解释

    • 静态成员函数不依赖于具体对象,因此不需要传递对象指针。


4. 传递参数到线程

#include <iostream>
#include <thread>

void threadFunction(int a, const std::string& str) {
    std::cout << "Thread received: " << a << ", " << str << std::endl;
}

int main() {
    int num = 42;
    std::string text = "Hello";

    std::thread t(threadFunction, num, text);

    t.join();

    std::cout << "Thread with arguments finished." << std::endl;
    return 0;
}
  • 解释

    • std::thread 会拷贝传递的参数,因此需要确保传递的对象是拷贝或可安全访问的。如果需要引用传递参数,使用 std::ref


5. 分离线程(Detached Threads)

如果不需要等待线程完成,可以将线程与主线程分离:

#include <iostream>
#include <thread>
#include <chrono>

void threadFunction() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Detached thread finished!" << std::endl;
}

int main() {
    std::thread t(threadFunction);
    t.detach();

    std::cout << "Main thread finished!" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待子线程完成输出
    return 0;
}
  • 注意

    • 分离线程不受主线程控制,主线程退出后线程可能继续运行,因此要小心资源的生命周期。


6. 线程安全与同步

在多线程中,多个线程可能同时访问共享资源,使用同步机制(如互斥锁 std::mutex)可以避免竞态条件。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void threadFunction(int id) {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Thread " << id << " is running." << std::endl;
}

int main() {
    std::thread t1(threadFunction, 1);
    std::thread t2(threadFunction, 2);

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

    return 0;
}

总结

  • 使用 std::thread 是 C++11 之后推荐的多线程方法。

  • 小心线程安全问题,必要时使用同步机制。

  • 在主线程退出前确保所有非分离线程已完成或显式分离。

遇到问题1

但是我现在有一个用法,我在一个类里面定义了一个函数,然后在另外一个类函数里面调用他,然后出现`error: invalid use of non-static member function 'void`

原因是将一个非静态成员函数 rcv_network_ 直接传递给 std::thread。这是不合法的,因为非静态成员函数依赖于一个类实例,需要通过实例调用。

原因分析

非静态成员函数有一个隐含的 this 指针参数,用于访问所属对象的成员变量。因此,不能直接将非静态成员函数作为线程入口传递给 std::thread。需要显式绑定 this 指针。


解决方法

1. 绑定对象实例

可以通过 std::bind 或直接使用 lambda 表达式,将非静态成员函数与对象实例绑定:

std::thread t1(&hf_uart2net::rcv_network_, this);

这是更常见和简单的写法。

示例代码

#include <iostream>
#include <thread>

class hf_uart2net {
public:
    void rcv_network_() {
        std::cout << "Receiving network data..." << std::endl;
    }

    void start_thread() {
        std::thread t1(&hf_uart2net::rcv_network_, this);  // 绑定 this
        t1.join();  // 等待线程完成
    }
};

int main() {
    hf_uart2net obj;
    obj.start_thread();
    return 0;
}

2. 将成员函数改为静态成员函数

如果 rcv_network_ 不需要访问类的成员变量,可以将其改为静态成员函数,这样就不需要绑定 this

#include <iostream>
#include <thread>

class hf_uart2net {
public:
    static void rcv_network_() {
        std::cout << "Receiving network data..." << std::endl;
    }

    void start_thread() {
        std::thread t1(rcv_network_);  // 静态成员函数不需要绑定对象
        t1.join();
    }
};

int main() {
    hf_uart2net obj;
    obj.start_thread();
    return 0;
}

3. 使用 lambda 表达式包装非静态成员函数

如果不想直接绑定 this,可以使用 lambda 表达式将成员函数封装起来:

#include <iostream>
#include <thread>

class hf_uart2net {
public:
    void rcv_network_() {
        std::cout << "Receiving network data..." << std::endl;
    }

    void start_thread() {
        std::thread t1([this]() { rcv_network_(); });  // 使用 lambda 表达式
        t1.join();
    }
};

int main() {
    hf_uart2net obj;
    obj.start_thread();
    return 0;
}

总结

  • 非静态成员函数需要绑定对象实例,例如 std::thread t1(&Class::Function, this);

  • 如果函数不依赖于类成员变量,可以将其改为静态成员函数。

  • 也可以通过 lambda 表达式捕获 this,从而调用非静态成员函数。