前言


一、线程优先级设置

C语言中的线程优先级是指操作系统为每个线程分配的一定的执行权重,通过调整线程的优先级,可以决定哪些线程先被执行,哪些线程后被执行。同时,线程优先级也影响着线程竞争CPU的时间片大小,优先级越高的线程获得的时间片就越大。

操作系统将优先级较高的线程分配更多的CPU时间片,以保证其能够及时地执行任务。当多个线程竞争CPU时间片时,操作系统会根据线程优先级的高低进行调度。当高优先级线程等待低优先级线程执行完毕后再继续执行时,就会出现所谓的线程饥饿现象,即高优先级线程无法得到足够的CPU时间,从而导致程序性能下降。

在 Linux 系统中,线程优先级是指操作系统对线程调度的优先级。优先级越高的线程会更快的得到 CPU 资源,从而更快地完成任务。

线程优先级在 Linux 中一般是一个整数,取值范围为 1 到 99。默认情况下,所有线程的优先级是相同的,都是中等优先级。

常用函数

1. pthread_attr_init函数:

该函数用于初始化线程属性对象,接受一个pthread_attr_t类型的指针作为参数。线程属性对象用于设置线程的一些属性,如调度策略、调度参数、堆栈大小等。

2. pthread_attr_setinheritsched函数:

该函数用于设置线程是否继承创建者的调度属性,默认情况下线程会继承创建者的调度属性。当创建线程时需要改变线程的调度属性或者跟创建者有不同的调度属性时,可以使用该函数去设置线程是否继承创建者的调度属性。

函数参数:

  • pthread_attr_t *attr:待设置的线程属性对象;

  • int inheritsched:确定线程是否继承调度属性的值,1表示继承,0表示不继承。

3. pthread_attr_setschedpolicy函数:

该函数用于设置线程的调度策略,即线程调度的方式。可以设置的调度策略如下:

  • SCHED_FIFO:先进先出调度策略,优先级高的线程先运行,优先级相等的按先进先出的顺序进行调度。

  • SCHED_RR:时间片轮转调度策略,每个线程分配一个时间片,时间片到了就切换到下一个线程,直到所有线程都运行完一次为止。

  • SCHED_OTHER:普通调度策略,由系统自动进行调度。

函数参数:

  • pthread_attr_t *attr:待设置的线程属性对象;

  • int policy:调度策略,可以是SCHED_FIFO、SCHED_RR或SCHED_OTHER。

4. pthread_attr_setschedparam函数:

该函数用于设置线程的调度参数,即线程的优先级。优先级越高的线程获取CPU时间的机会越大。

函数参数:

  • pthread_attr_t *attr:待设置的线程属性对象;

  • const struct sched_param *param:线程的调度参数,包括优先级和调度策略

// 线程的优先级可以通过设置线程属性来实现。优先级的值越高,表示该线程具有更高的调度优先级。
// thread init
pthread_t audio_tid;   // 创建线程
pthread_attr_t thread_pro;  // 线程属性,默认为NULL
pthread_attr_init(&thread_pro);  // 属性变量初始化
pthread_attr_setschedpolicy(&thread_pro, SCHED_RR);  // 设置调度策略
pthread_attr_setinheritsched(&thread_pro, PTHREAD_EXPLICIT_SCHED);  // 设置是否继承父线程的调度属性
struct sched_param s_param;  // 设置参数
s_param.sched_priority = sched_get_priority_max(SCHED_RR); // 优先级设置,获取最大优先级
pthread_attr_setschedparam(&thread_pro, &s_param);   // 设置线程schedparam属性,即调用的优先级
ret = pthread_create(&audio_tid, &thread_pro, AudioThread, this);  // AudioThread为线程开始																	 // 执行的函数

使用技巧

pthread_attr_setschedpolicy可以设置以下线程优先级:

  1. SCHED_OTHER:默认优先级范围,线程以时间共享的方式利用CPU,不可设置优先级等级。

  2. SCHED_FIFO:FIFO先进先出调度策略,采用该策略的线程具有较高的优先级并始终保持对CPU的占用。

  3. SCHED_RR:时间片轮转策略,线程通过循环地抢占CPU,每个线程分配一个时间片,当时间片用完后,系统重新为该线程分配一个时间片。

使用场景:

  1. 在需要及时响应的任务中,如实时音视频、控制系统等领域,可以将线程设置为SCHED_FIFO或SCHED_RR策略,以保证任务得到及时处理。

  2. 对于一些需要集中精力处理的任务,可以提高线程优先级以确保任务能够得到迅速的响应。

  3. 对于一些后台任务,可以设置较低的优先级以避免对系统性能造成不必要的影响。

通过pthread_attr_setschedpolicy函数可以设置线程的调度策略和优先级,其中SCHED_RR调度策略是时间片轮转方式。调用该函数需要传入一个pthread_attr_t类型的参数和一个int类型的参数,用于设置调度策略和优先级。

例如,以下代码将线程的调度策略设置为SCHED_RR,优先级为10:

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
struct sched_param param;
param.sched_priority = 10;
pthread_attr_setschedparam(&attr, &param);

其中,param.sched_priority的值越大,线程的优先级越高。需要注意的是,SCHED_RR调度策略中每个线程的执行时间片长度是不确定的,取决于系统中所有线程的优先级和数量等因素。

一个进程中同时包含设置SCHED_OTHER、SCHED_FIFO、SCHED_RR的线程时,处理流程如下:

  1. 对于设置了SCHED_FIFO和SCHED_RR调度策略的线程,它们会按优先级大小进行调度,如果一个SCHED_FIFO线程正在执行,只有当它结束或者被挂起时,才会调度其他线程。而对于SCHED_RR线程,它们也会按优先级大小调度,但它们会分配一个固定的时间片,在该时间内执行完或自愿放弃CPU后,才会进行调度。

  2. 对于设置了SCHED_OTHER调度策略的线程,它们是相对较低优先级的线程,它们会依靠时间片轮转的方式来进行调度,不会干扰SCHED_FIFO和SCHED_RR线程的执行。当所有SCHED_FIFO和SCHED_RR线程都没有需要执行时,才会轮到SCHED_OTHER线程执行。

在一个进程中同时包含不同调度策略的线程可以实现不同的执行需求,高优先级的SCHED_FIFO和SCHED_RR线程保证了实时性,而SCHED_OTHER线程可以在不影响实时性的同时进行后台工作。

如果SCHED_FIFO中的线程一直在执行,SCHED_OTHER线程和SCHED_RR中的线程将不会得到执行机会。因为SCHED_FIFO是实时调度策略,具有最高的优先级,优先级比SCHED_OTHER和SCHED_RR高,所以先被执行。只有当SCHED_FIFO中的线程阻塞或者退出后,才会轮到优先级较低的SCHED_OTHER和SCHED_RR中的线程获取CPU执行时间。

获取最大优先级

可以通过调用sched_get_priority_max函数来获取SCHED_FIFO可以设置的最大sched_priority参数。它返回的是当前系统中SCHED_FIFO可以设置的最大优先级值。示例代码如下:

#include <sched.h>
#include <stdio.h>
int main() {
    int max_priority = sched_get_priority_max(SCHED_FIFO);
    printf("SCHED_FIFO max priority: %d\n", max_priority);
    return 0;
}

获取线程id

std::this_thread::get_id 是C++11标准库中的函数,用于获取当前线程的标识符,返回一个std::thread::id类型的对象。而 pthread_self() 是POSIX线程库中的函数,也用于获取当前线程的标识符,返回一个pthread_t类型的对象。

在功能上,这两个函数是相同的,都可以用来获取当前线程的标识符。区别主要在于数据类型和跨平台性。

std::thread::id 是C++11中新增的类型,是一个轻量级的对象,可以跨平台使用。而pthread_t 是POSIX线程库中定义的类型,只能在支持POSIX线程库的系统上使用,不能跨平台。

因此,在C++11标准库中,建议使用std::this_thread::get_id()来获取当前线程的标识符,能够更好地保证代码的可移植性。


二、使用示例

线程调度

获取当前线程的调度属性

#include <stdio.h>
#include <pthread.h>
#include <sched.h>
void *thread_func(void *arg) {
    pthread_t tid = pthread_self();  // 获取当前线程的pthread id
    int policy;
    struct sched_param param;
    pthread_getschedparam(tid, &policy, &param);
    printf("Thread %ld scheduling policy is %s, priority is %d\n", (long)tid,
           (policy == SCHED_FIFO ? "SCHED_FIFO" :
            (policy == SCHED_RR ? "SCHED_RR" :
             (policy == SCHED_OTHER ? "SCHED_OTHER" : "unknown"))),
           param.sched_priority);
    return NULL;
}
int main() {
    pthread_t tid;
    pthread_attr_t attr;
    struct sched_param param;
    // 初始化attr为默认值
    pthread_attr_init(&attr);
    // 设置线程调度策略为SCHED_FIFO
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    // 设置线程优先级为99
    param.sched_priority = 99;
    pthread_attr_setschedparam(&attr, &param);
    pthread_create(&tid, &attr, thread_func, NULL);
    pthread_join(tid, NULL);
    return 0;
}

线程属性设置及获取demo

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sched.h>
void *thread_func(void *arg) {
    printf("I'm a new thread.\n");
    pthread_exit(NULL);
}
int main() {
    int policy;
    struct sched_param param;
    // 初始化线程属性
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    // 设置继承调度策略
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    // 设置线程调度策略为SCHED_FIFO
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    // 设置线程调度参数
    param.sched_priority = 80;
    pthread_attr_setschedparam(&attr, ¶m);
    // 创建新线程并运行
    pthread_t new_thread;
    if (pthread_create(&new_thread, &attr, thread_func, NULL) != 0) {
        perror("pthread_create error");
        return 1;
    }
    // 获取线程调度策略和参数
    pthread_attr_getschedpolicy(&attr, &policy);
    pthread_attr_getschedparam(&attr, ¶m);
    // 输出线程调度策略和参数
    printf("Thread policy: ");
    switch (policy) {
        case SCHED_FIFO:
            printf("FIFO\n");
            break;
        case SCHED_RR:
            printf("RR\n");
            break;
        case SCHED_OTHER:
            printf("OTHER\n");
            break;
        default:
            printf("UNKNOWN\n");
    }
    printf("Thread priority: %d\n", param.sched_priority);
    // 等待子线程结束
    if (pthread_join(new_thread, NULL) != 0) {
        perror("pthread_join error");
        return 1;
    }
    return 0;
}

线程使用

不同方式的线程创建

pthread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void* thread_func(void* arg)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("Thread %d running\n", *((int*) arg));
        sleep(1);
    }
    return NULL;
}
int main()
{
    int i;
    pthread_t tid[2];
    int arg[2] = {1, 2};
    for (i = 0; i < 2; i++) {
        pthread_create(&tid[i], NULL, thread_func, &arg[i]);
    }
    for (i = 0; i < 2; i++) {
        pthread_join(tid[i], NULL);
    }
    printf("Main thread exiting\n");
    return 0;
}

代码中使用了两个线程,它们都执行了相同的函数thread_func,同时main线程等待这两个线程执行完毕后才退出。

线程的创建:pthread_create函数用于创建线程,它需要传入4个参数:新线程的地址(tid),线程属性(NULL表示采用默认属性),线程执行的函数名(thread_func),和传给线程执行函数的参数(&arg[i])。

线程执行函数:函数thread_func接受一个指针参数arg,用于指定线程的编号。函数中使用了一个计数器变量i,在循环中输出线程编号和计数器变量i的值。由于两个线程同时执行,所以线程的输出语句可能会交错出现。

线程同步:在main函数中,使用pthread_join函数告诉主线程要等到tid[0]和tid[1]所对应的线程都执行完毕后才能退出。这样可以保证main线程在所有子线程都退出后才能结束程序,并能够收到线程的返回值。

线程的销毁:在本例中,并没有使用pthread_exit函数显式地销毁线程,因为线程执行函数已经自己返回了。如果需要显式地销毁线程,可以调用pthread_exit函数

std::thread
#include <iostream>
#include <thread>
void foo(int x) {
    std::cout << "Function foo called with argument " << x << std::endl;
}
int main() {
    // 创建新线程并执行函数
    std::thread t(foo, 10);
    // 主线程等待子线程执行完毕
    t.join();
    // 输出信息并销毁子线程
    std::cout << "Thread has been joined and destroyed" << std::endl;
    return 0;
}

在这个示例中,我们创建了一个新的std::thread对象,并使用foo函数作为它要执行的函数,同时将10作为foo的参数传递进去。我们在主线程中使用t.join()等待子线程执行完毕再继续执行,最后销毁子线程。

注意,如果我们忘记调用join()将会发生什么:程序将会在主线程退出时终止子线程的执行,这可能导致一些未定义行为。因此,在使用std::thread时,我们必须确保所有子线程在主线程结束时都已经退出。

std::async
#include <iostream>
#include <future>
int calc_sum(int a, int b) {
    int sum = 0;
    for(int i=a; i<=b; i++) {
        sum += i;
    }
    return sum;
}
int main() {
    // 1. 创建异步任务
    std::future<int> fut = std::async(std::launch::async, calc_sum, 1, 100);
    
    // 2. 在主线程中执行其他任务
    for(int i=0; i<10; i++) {
        std::cout << "do something else." << std::endl;
    }
    
    // 3. 等待异步任务完成,并获取结果
    int res = fut.get();
    std::cout << "result = " << res << std::endl;
    
    return 0;
}
  1. std::async函数的第一个参数指定启动策略,可以是std::launch::async(创建新线程执行任务)或std::launch::deferred(延迟执行,等到调用getwait时才执行任务)。

  2. std::async函数的后面的参数是要执行的函数及其参数。

  3. std::future类型的对象可以通过调用getwait函数等待异步执行的结果,并获取结果。

  4. 等待异步任务完成时,当前线程会被阻塞,直到任务完成。如果不等待异步任务完成,而是直接销毁std::future对象,会导致程序崩溃。

创建线程的区别

std::thread和pthead的区别

std::thread和pthread都可以创建线程的API,但是有以下不同点:

  1. std::thread是C++11标准库中的线程API,而pthread是POSIX标准的线程API,两者的调用方式和语法有所不同。

  2. std::thread是C++11面向对象的API,它以类和对象的形式封装了线程的相关操作,使得线程的管理更加简单方便;而pthread则是面向过程的API,它需要手动创建和操作线程对象,比较繁琐。

  3. std::thread的跨平台性更强,可以在所有支持C++11的平台上运行,而pthread只能在支持POSIX标准的平台上运行。

  4. std::thread提供了一些C++11独有的特性,比如可以采用Lambda表达式来定义线程函数,避免了定义全局函数的麻烦,还提供了方便的线程同步机制,如std::mutex、std::condition_variable等。

综上所述,std::thread比pthread更加面向对象、跨平台、方便和安全,但是如果需要兼容旧的POSIX代码或使用特定的线程特性,pthread仍然是一个不错的选择。

std::thread和std::async的区别

std::thread和std::async都是C++11中的并发库,但它们的用途和工作方式略有不同。

std::thread是一种基本的并发机制,它可以启动一个线程,该线程会追踪它自己的执行状态,并在需要时交换CPU时间片以使得其他线程得以执行。std::thread需要程序员手动控制线程的生命周期,包括创建、销毁和同步等。

std::async是一种高层次的并发机制,它可以自动创建一个线程或者复用线程池中的线程,执行指定的异步任务,并返回一个std::future对象,表示异步任务返回的值。std::async会根据一些启发式的规则来决定使用哪种方式(线程或线程池)执行异步任务,以最大程度地减少线程的创建和销毁。

在使用std::thread时,如果需要等待线程的执行结果,需要手动使用线程同步机制(如std::mutex和std::condition_variable)来等待线程执行完毕。而在使用std::async时,可以直接使用std::future的成员函数等待异步任务的完成,并获取异步任务的结果。此外,std::async还提供了一些控制异步任务执行的选项,如std::launch::async和std::launch::d eferred。

综上所述,std::thread和std::async在很多情况下都可以用于并发编程,但std::async更加简单方便,并且对于大多数的异步任务使用场景,std::async的表现更加优秀。

std::thread和std::async都是C++的多线程库,但是它们有以下区别:
1.用法不同
std::thread的用法是:创建一个线程,然后执行指定的函数。
std::async的用法是:在另一个线程中异步执行指定的函数,并且可以获得该函数的返回值。
2.返回值不同
std::thread不会返回函数的返回值,因此必须使用共享数据进行通信。
std::async会返回指定函数的返回值。
3.默认参数不同
std::thread的默认参数是std::launch::deferred,表示指定函数的执行将延迟到调用.get()或.wait()时。
std::async的默认参数是std::launc::async,表示指定函数应该立即在一个新线程中执行。
4.有可能阻塞
std::thread的join()和std::async的get()会阻塞调用线程直到结束。
5.线程数量不同
std::thread的数量没有限制,可以创建多个线程。
std::async的数量是由库实现者控制的,可以基于硬件限制或性能考虑对其数量进行限制。
总之,std::thread用于创建新线程,并从中获得结果,而std::async用于在一个或多个并发任务中异步执行函数,并获得该函数的返回值。
std::async和pthread的区别

pthread是一个POSIX标准定义的线程API,std::async是C++11标准库中提供的异步任务执行的工具。

pthread需要手动创建和管理线程,包括线程的启动、函数参数的传递、线程的同步、结束等等。而std::async利用了C++11的新特性,可以方便地在后台执行一个函数,无需手动创建和管理线程,同时可以设置执行策略。

pthread更加底层,需要手动处理锁和同步等问题,对于高并发场景更有优势;而std::async更适合执行一些简单的计算任务,对于大量IO操作的任务也有很好的支持。

在C++11及之后的版本中,std::thread、std::future和std::async的使用已经取代了pthread作为C++多线程编程的主要方式。


使用技巧

std::thread 创建的线程修改线程优先级

在 C++11 标准中,std::thread 类库提供了一种简单的创建线程的方法,但并未提供直接修改线程调度策略和优先级的方法。

如果需要修改线程的调度策略和优先级,可以使用 pthread 库中的函数。

以下是一个示例代码,用于创建一个线程并修改其调度策略和优先级:

#include <iostream>
#include <thread>
#include <pthread.h>
#include <sched.h>
void thread_func()
{
    // 线程执行的任务
}
int main()
{
    std::thread t(thread_func);
    // 修改线程的调度策略和优先级
    int policy = SCHED_RR; // 设置为轮流调度
    int priority = 10; // 设置优先级为 10
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, policy);
    sched_param param;
    param.sched_priority = priority;
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    pthread_t thread_handle = t.native_handle();
    pthread_setschedparam(thread_handle, policy, &param);
    t.join();
    return 0;
}

在上述代码中,首先创建了一个 std::thread 对象 t,然后使用 pthread 库中的函数修改该线程的调度策略和优先级。

通过 pthread 库中的 pthread_attr_t 类型的变量和相关函数,可以使用轮流调度策略(SCHED_RR)和优先级(priority)为 10 来重新设置线程参数。最后,将线程参数应用到线程 handle 上,即可修改线程的调度策略和优先级。

注意:在使用 pthread 库时,需要通过 t.native_handle() 获取线程的原生句柄,然后才能使用相关函数对线程进行操作。同时要注意在进行修改前,必须等待线程 t 执行完毕并退出,否则可能会产生未定义的行为。

std::async创建的线程优先级修改

#include <iostream>
#include <future>
#include <pthread.h>
void worker(int id) {
  std::cout << "Thread " << id << " started." << std::endl;
  // 该线程的调度策略和优先级将在此处修改
  pthread_t thread = pthread_self();
  struct sched_param sched_param;
  sched_param.sched_priority = 10; // 设置优先级
  pthread_setschedparam(thread, SCHED_FIFO, &sched_param); // 设置调度策略
  std::cout << "Thread " << id << " changed." << std::endl;
}
int main() {
  std::cout << "Main thread started." << std::endl;
  std::vector<std::future<void>> futures;
  for(int i = 0; i < 5; i++) {
    futures.emplace_back(std::async(std::launch::async, worker, i));
  }
  for(auto& f : futures) {
    f.get();
  }
  std::cout << "Main thread finished." << std::endl;
  return 0;
}

在这个示例中,我们使用了std::async函数创建了5个异步线程,并且使用了pthread库里的pthread_self()和pthread_setschedparam()函数分别获取和修改了线程的ID以及调度策略和优先级。具体来说:

  • 在worker函数中,我们首先输出了线程的ID,然后使用pthread_self()函数获取了当前线程的ID,并将其保存为一个pthread_t类型变量thread。

  • 然后,我们创建了一个sched_param结构体变量,将其优先级设置为10。注意,优先级的值通常范围在1到99之间,值越大表示优先级越高。

  • 最后,我们使用pthread_setschedparam()函数设置了线程的调度策略为SCHED_FIFO,并将sched_param变量传递给函数,从而修改了线程的调度策略和优先级。

在实际运行中,我们可以看到输出内容

Main thread started.
Thread 0 started.
Thread 2 started.
Thread 1 started.
Thread 4 started.
Thread 3 started.
Thread 0 changed.
Thread 1 changed.
Thread 3 changed.
Thread 4 changed.
Thread 2 changed.
Main thread finished.

从输出可以看出,每个线程都按照我们指定的调度策略和优先级运行了。由于我们将优先级设置为10,因此线程的执行顺序可能并不是完全按照线程创建的顺序,而是会受到优先级的影响。

std::thread条件变量

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::queue<int> myQueue;
std::mutex myMutex;
std::condition_variable myCondVar;
void producer()
{
    for (int i = 1; i <= 10; ++i)
    {
        std::unique_lock<std::mutex> lock(myMutex);
        myQueue.push(i);
        std::cout << "Produced: " << i << std::endl;
        lock.unlock(); // 必须先解锁互斥锁才能通知条件变量
        myCondVar.notify_one(); // 通知消费者线程
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 暂停100毫秒
    }
}
void consumer()
{
    while (true)
    {
        std::unique_lock<std::mutex> lock(myMutex);
        while (myQueue.empty())
        {
            // 队列为空时,等待通知
            myCondVar.wait(lock);
        }
        int value = myQueue.front();
        myQueue.pop();
        std::cout << "Consumed: " << value << std::endl;
        lock.unlock(); // 必须先解锁互斥锁才能通知条件变量
        myCondVar.notify_one(); // 通知生产者线程
        std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 暂停500毫秒
    }
}
int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}

上面的代码中,生产者线程不断往队列中添加元素,并通知消费者线程;消费者线程则不断从队列中取出元素,并通知生产者线程。为了避免竞争条件,使用了互斥锁对队列进行保护,并使用条件变量进行线程同步。具体来说,当队列为空时,消费者线程会调用 ‘wait()’ 方法,使线程处于等待状态,直到有元素被添加到队列中并调用 ‘notify_one()’ 方法通知它;当队列满时,生产者线程会调用 ‘wait()’ 方法,使线程处于等待状态,直到有元素被取出队列并调用 ‘notify_one()’ 方法通知它。这样就能保证生产者和消费者线程之间的同步,避免竞争问题。

pthread条件变量

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 创建互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 创建条件变量
int flag = 0; // 标志位
void *thread1(void *arg) { // 等待条件变量的线程
    pthread_mutex_lock(&mutex); // 加锁
    printf("Thread1 start\n");
    while(flag != 1) { // 循环等待信号
        pthread_cond_wait(&cond, &mutex); // 阻塞等待
    }
    printf("Thread1 end\n");
    pthread_mutex_unlock(&mutex); // 解锁
    pthread_exit(NULL);
}
void *thread2(void *arg) { // 发送条件变量信号的线程
    pthread_mutex_lock(&mutex); // 加锁
    printf("Thread2 start\n");
    sleep(2); // 等待2秒钟
    flag = 1; // 修改标志位
    pthread_cond_signal(&cond); // 发送信号
    printf("Thread2 end\n");
    pthread_mutex_unlock(&mutex); // 解锁
    pthread_exit(NULL);
}
int main() {
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, thread1, NULL); // 创建线程1
    pthread_create(&tid2, NULL, thread2, NULL); // 创建线程2
    pthread_join(tid1, NULL); // 等待线程1结束
    pthread_join(tid2, NULL); // 等待线程2结束
    return 0;
}

注:

  1. 使用 pthread_cond_wait 函数时需要先加锁,而 pthread_cond_signal 函数发送信号时不需要加锁。

  2. 等待条件变量信号的线程等待时,会自动解锁互斥锁,等接收到信号后重新加锁互斥锁,继续执行。

  3. 发送条件变量信号的线程发送信号后,等待条件变量信号的线程会从阻塞状态中被唤醒,重新加锁互斥锁,继续执行

总结

本文主要介绍了线程调度策略及优先级调整,std::thread、std::async、pthread的使用和区别,条件变量的使用,std::thread和std::async创建线程优先级的修改

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐