C++ thread 基本用法

1.thread类定义

表示各个执行线程的类。一个初始化的线程对象表示活动的执行线程; 这样的线程对象是可连接的,并且具有唯一的线程ID。

缺省构造(未初始化)的线程对象不可join,并且其线程ID对于所有不可join的线程都是通用的。C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。

2.构造函数

转自: https://blog.csdn.net/coolwriter/article/details/79883253

(1).默认构造函数,创建一个空的 thread 执行对象。
(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
例子:

#include<thread>  
#include<chrono>  
using namespace std;  
void fun1(int n)  //初始化构造函数  
{  
    cout << "Thread " << n << " executing\n";  
    n += 10;  
    this_thread::sleep_for(chrono::milliseconds(10));  
}  
void fun2(int & n) //拷贝构造函数  
{  
    cout << "Thread " << n << " executing\n";  
    n += 20;  
    this_thread::sleep_for(chrono::milliseconds(10));  
}  
int main()  
{  
    int n = 0;  
    thread t1;               //t1不是一个thread  
    thread t2(fun1, n + 1);  //按照值传递  
    t2.join();  
    cout << "n=" << n << '\n';  
    n = 10;  
    thread t3(fun2, ref(n)); //引用  
    thread t4(move(t3));     //t4执行t3,t3不是thread  
    t4.join();  
    cout << "n=" << n << '\n';  
    return 0;  
}  
运行结果:  
Thread 1 executing  
n=0  
Thread 10 executing  
n=30
#include<thread>  
#include<chrono>  
using namespace std;  
void fun1(int n)  //初始化构造函数  
{  
    cout << "Thread " << n << " executing\n";  
    n += 10;  
    this_thread::sleep_for(chrono::milliseconds(10));  
}  
void fun2(int & n) //拷贝构造函数  
{  
    cout << "Thread " << n << " executing\n";  
    n += 20;  
    this_thread::sleep_for(chrono::milliseconds(10));  
}  
int main()  
{  
    int n = 0;  
    thread t1;               //t1不是一个thread  
    thread t2(fun1, n + 1);  //按照值传递  
    t2.join();  
    cout << "n=" << n << '\n';  
    n = 10;  
    thread t3(fun2, ref(n)); //引用  
    thread t4(move(t3));     
    t4.join();  
    cout << "n=" << n << '\n';  
    return 0;  
}  
运行结果:  
Thread 1 executing  
n=0  
Thread 10 executing  
n=30

其中t3的move,移动构造函数会将 t3 持有的线程句柄转移到 t4,并将 t3 标记为没有关联任何线程的状态。t3 在移动操作之后变为不可 joinable 的状态,因为它不再持有线程的所有权。试图使用 t3 再进行操作(如 join 或 detach)将导致未定义行为。

  • 原来由 t3启动的线程会继续执行 someFunc,但现在这个线程的所有权属于 t4
  • 由于线程是在 t3 创建时启动的,移动操作不会重新启动或中断线程,线程继续执行 someFunc,只是现在 t4 是它的控制对象。

3.其他成员函数

 4.join和detach

可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。用于thread对象的生命周期管理。

在 C++ 中,线程(std::thread 对象)必须在销毁之前被主线程 join 或者设置为 detached,这是因为如果不这样做,程序可能会出现资源泄漏或者未定义行为。每个 std::thread 对象都会占用一定的系统资源(如线程句柄、堆栈空间等)。如果一个 std::thread 对象在销毁时仍然是 joinable 的,并且没有被 join 或 detach,这将导致程序的未定义行为。这是因为 C++ 线程库没有明确指定在这种情况下应该执行的操作。

join: 主线程等待子线程完成执行。当主线程调用子线程的 join 方法时,主线程将阻塞,直到子线程完成。这确保了子线程的资源能够被正确回收。

std::thread t(some_function);
t.join(); // 主线程等待 t 线程完成

 detach: 将子线程与主线程分离,让子线程在后台独立运行。当主线程调用子线程的 detach 方法时,子线程将独立执行,主线程不会等待子线程完成。分离的线程在完成后会自动释放其资源。

std::thread t(some_function);
t.detach(); // t 线程在后台运行,主线程不再等待

错误用法:

int main() {
    std::thread t(thread_function);
    // 未调用 join 或 detach,可能导致未定义行为
    return 0;
}

当调用 detach 时,线程会自动释放资源,并不会导致资源泄露。分离的线程在其生命周期结束时,由操作系统或线程库负责清理其资源。

C语言中的线程是一种轻量级的进程,它可以在同一个进程中并发执行多个任务。线程可以共享进程的资源,如内存空间、文件句柄等,但每个线程都拥有自己的寄存器和栈空间。线程的使用可以提高程序的运行效率,增强程序的并发性能。 以下是C语言中线程的常用用法: 1. 创建线程 创建线程需要使用pthread_create()函数。它的原型如下: ``` int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); ``` 参数说明: - thread:指向线程标识符的指针。 - attr:线程属性,通常为NULL。 - start_routine:线程函数的指针。 - arg:传递给线程函数的参数。 示例代码: ``` #include <pthread.h> #include <stdio.h> void* thread_function(void* arg) { printf("Thread is running.\n"); pthread_exit(NULL); } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_function, NULL); printf("Thread created.\n"); pthread_join(tid, NULL); printf("Thread finished.\n"); return 0; } ``` 2. 终止线程 线程可以通过调用pthread_exit()函数来终止自己。如果一个线程已经被终止,其他线程可以通过pthread_join()函数来等待它的结束。如果一个线程不希望其他线程等待它的结束,可以使用pthread_detach()函数将它分离。 示例代码: ``` #include <pthread.h> #include <stdio.h> void* thread_function(void* arg) { printf("Thread is running.\n"); pthread_exit(NULL); } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_function, NULL); printf("Thread created.\n"); pthread_join(tid, NULL); printf("Thread finished.\n"); return 0; } ``` 3. 线程同步 在多线程编程中,经常需要进行线程同步,以保证各个线程之间的顺序和正确性。C语言提供了多种线程同步的机制,如互斥锁、条件变量、信号量等。 互斥锁:在多个线程访问共享资源时,需要保证同时只有一个线程能够访问,这时就需要使用互斥锁来保护共享资源。 示例代码: ``` #include <pthread.h> #include <stdio.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int counter = 0; void* thread_function(void* arg) { int i; for (i = 0; i < 100000; i++) { pthread_mutex_lock(&mutex); counter++; pthread_mutex_unlock(&mutex); } pthread_exit(NULL); } int main() { pthread_t tid1, tid2; pthread_create(&tid1, NULL, thread_function, NULL); pthread_create(&tid2, NULL, thread_function, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); printf("Counter value: %d\n", counter); return 0; } ``` 条件变量:条件变量用于在多个线程之间传递信号,以便线程之间能够相互通信。 示例代码: ``` #include <pthread.h> #include <stdio.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int counter = 0; void* thread_function(void* arg) { pthread_mutex_lock(&mutex); while (counter < 3) { pthread_cond_wait(&cond, &mutex); } pthread_mutex_unlock(&mutex); printf("Thread finished.\n"); pthread_exit(NULL); } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_function, NULL); pthread_mutex_lock(&mutex); counter++; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); pthread_mutex_lock(&mutex); counter++; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); pthread_mutex_lock(&mutex); counter++; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); pthread_join(tid, NULL); printf("All threads finished.\n"); return 0; } ``` 信号量:信号量用于在多个线程之间同步访问共享资源。 示例代码: ``` #include <pthread.h> #include <semaphore.h> #include <stdio.h> sem_t sem; int counter = 0; void* thread_function(void* arg) { int i; for (i = 0; i < 100000; i++) { sem_wait(&sem); counter++; sem_post(&sem); } pthread_exit(NULL); } int main() { pthread_t tid1, tid2; sem_init(&sem, 0, 1); pthread_create(&tid1, NULL, thread_function, NULL); pthread_create(&tid2, NULL, thread_function, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(&sem); printf("Counter value: %d\n", counter); return 0; } ``` 4. 线程池 线程池是一种常用的线程管理方法,它可以预先创建一些线程,并将它们保存在一个线程池中,以便随时调用。这种方法可以避免频繁地创建和销毁线程,提高程序的效率。 示例代码: ``` #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define THREAD_POOL_SIZE 5 typedef struct { pthread_t thread_id; int busy; } thread_t; thread_t thread_pool[THREAD_POOL_SIZE]; void* thread_function(void* arg) { int index = *(int*)arg; printf("Thread %d is running.\n", index); while (1) { // do something thread_pool[index].busy = 0; } pthread_exit(NULL); } int main() { int i; for (i = 0; i < THREAD_POOL_SIZE; i++) { pthread_create(&thread_pool[i].thread_id, NULL, thread_function, &i); } while (1) { // do something for (i = 0; i < THREAD_POOL_SIZE; i++) { if (!thread_pool[i].busy) { thread_pool[i].busy = 1; break; } } } return 0; } ``` 以上是C语言中线程的常用用法。在实际使用中,需要根据具体情况选择合适的线程同步方法,以保证程序的正确性和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值