线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程:是多任务处理的一种特殊形式。

一般情况下,两种类型的多任务处理:基于进程和基于线程

  • 基于进程的多任务处理是程序的并发执行。
  • 基于线程的多任务处理是同一程序的片段的并发执行。
    • 并发:多个任务在时间片段内交替执行,表现出同时进行的效果。
    • 并行:多个任务在多个处理器或处理器核上同时执行。

C++ 多线程编程涉及在一个程序中创建和管理多个并发执行的线程。

实现多线程

在C++ 11 新特性中std::thread对linux中的pthread和windows中的Win32 API进行封装,支持跨平台、移动语义等特点,本文主要使用std::thread,对pthread和Thread简单使用。

使用<windows.h>实现

windows下的原生API进行创建线程。

  • 接口
//创建线程
HANDLE CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 安全属性
    _In_ SIZE_T dwStackSize,                           // 堆栈大小
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,        // 线程函数地址
    _In_opt_ LPVOID lpParameter,                       // 线程参数
    _In_ DWORD dwCreationFlags,                        // 创建标志
    _Out_opt_ LPDWORD lpThreadId                       // 接收线程ID
);

//关闭句柄
CloseHandle(
    _In_ _Post_ptr_invalid_ HANDLE hObject
    );

//待线程结束
//等待事件、信号量等同步对象
DWORD WaitForSingleObject(
    _In_ HANDLE hHandle,        // 要等待的对象句柄
    _In_ DWORD dwMilliseconds   // 超时时间(毫秒)
);

// 使用标志变量让线程自然退出
// 使用事件对象通知线程退出
BOOL TerminateThread(
    _In_ HANDLE hThread,   // 要终止的线程句柄
    _In_ DWORD dwExitCode  // 线程退出码
);

// 检查线程是否仍在运行
// 获取线程的执行结果
// 调试和错误处理
BOOL GetExitCodeThread(
    _In_ HANDLE hThread,         // 线程句柄
    _Out_ LPDWORD lpExitCode     // 接收退出码的指针
);

// 设置当前线程属性(优先级、亲和性等)
// 在线程函数中操作自身
HANDLE GetCurrentThread(VOID);  // 无参数,返回当前线程伪句柄
  • 实现
#include <windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI threadrun(LPVOID lpParamter)
{
    for (int i = 0; i < 10; i++) {
        cout << "Threadrun:" << i << endl;
        Sleep(50);
    }
    return 0;
}

int main()
{
    HANDLE hThread = CreateThread(NULL, 0, threadrun, NULL, 0, NULL);
    CloseHandle(hThread); //CloseHandle只是关闭了句柄,并不会终止线程。但是,如果主线程退出,进程会终止,所有线程都会结束。

    for (int i = 0; i < 10; i++) {
        cout << "Main:" << i << endl;
        Sleep(10);
    }

    //WaitForSingleObject(hThread, INFINITE); //等待线程完成 ,前提是hThread没有关闭
    return 0;
}

使用pthread实现

  • 接口
// 创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg);

// 线程退出
void pthread_exit(void *retval);

// 等待线程结束
int pthread_join(pthread_t thread, void **retval);

// 分离线程
int pthread_detach(pthread_t thread);


// 取消线程
int pthread_cancel(pthread_t thread);

// 获取当前线程ID
pthread_t pthread_self(void);

// 比较线程ID
int pthread_equal(pthread_t t1, pthread_t t2);

// 初始化线程属性
int pthread_attr_init(pthread_attr_t *attr);

// 销毁线程属性
int pthread_attr_destroy(pthread_attr_t *attr);

// 设置分离状态
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

// 获取分离状态
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

// 设置堆栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

// 设置调度策略
/*
 * 参数:policy -
 *   SCHED_FIFO    先进先出
 *   SCHED_RR      轮转
 *   SCHED_OTHER   其他(默认)
 */
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

  • 实现
#include <pthread.h>      // POSIX 线程库头文件
#include <stdio.h>        // 标准输入输出头文件
#include <stdlib.h>       // 标准库头文件(包含exit等函数)
#include <unistd.h>       // Unix标准库头文件,包含getpid(), sleep()等系统调用
#include <iostream>       // C++标准输入输出流
#include <cstring>
using namespace std;      // 使用std命名空间

// 线程函数 - 子线程的入口点
// 参数:threadid - 传递给线程的参数(这里用作线程标识符)
// 返回值:void* - 线程退出时可以返回一个指针(这里返回NULL)
void *PrintThread(void *threadid)
{
    // 获取当前线程ID的方式:
    // 使用pthread_self()获取POSIX线程ID(pthread_t类型)
    pthread_t id = pthread_self();
    pid_t tid = getpid();  // 这获取的是进程ID,不是线程ID

    cout << "ChildThread:" << " pid=" << tid << endl;  // 这里打印的是进程ID
        cout << "ChildSelf:" << " id=" << id << endl;
    for(int i = 0; i < 100; i++){
        cout << i << endl;
        sleep(1);              // 休眠1秒,模拟耗时操作
    }

    // 线程退出
    pthread_exit(NULL);        // 显式退出线程,参数NULL表示不返回任何值
    // 或者直接: return NULL;  // 等效的退出方式
}


int main(int argc, char *argv[])
{
    // 获取当前进程ID(注意:主线程也在同一个进程中)
    pid_t tid = getpid();  // 获取当前进程ID
    cout << "main thread" << " pid=" << tid << endl;  // 打印主线程所在进程的ID
    pthread_t id = pthread_self();
    cout << "main Self:" << " id=" << id << endl;

    pthread_t thread;    // 线程句柄/标识符(用于引用创建的线程)
    pthread_attr_t attr; //线程属性对象
    int result;              // 存储函数返回码(return code)
    long param = 1;          // 线程参数,这里作为线程ID使用(值为1)

    result = pthread_attr_init(&attr); //初始化属性
    if (result != 0) {
        cerr << "Error: pthread_attr_init failed: " << strerror(result) << endl;
        return 0;
    }

    //设置分离状态 PTHREAD_CREATE_JOINABLE 或 PTHREAD_CREATE_DETACHED
    result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    if (result == 0) {
        cout << "设置线程为可连接状态(JOINABLE)" << endl;
    }

    // 设置堆栈大小(256KB)
    size_t stacksize = 256 * 1024;  // 256KB
    result = pthread_attr_setstacksize(&attr, stacksize);
    if (result == 0) {
        size_t actual_stacksize;
        pthread_attr_getstacksize(&attr, &actual_stacksize);
        cout << "设置堆栈大小: " << actual_stacksize << " bytes" << endl;
    }

    // 设置调度策略  普通应用用 SCHED_OTHER分时调度
    result = pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
    if (result == 0) {
        cout << "设置调度策略: SCHED_OTHER" << endl;
    }

    // 设置继承调度属性(使用显式设置而非继承)
    result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    if (result == 0) {
        cout << "设置显式调度继承" << endl;
    }

    //设置竞争范围(Linux只支持系统级)  Linux只支持 PTHREAD_SCOPE_SYSTEM
    result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    if (result == 0) {
        cout << "设置竞争范围: PTHREAD_SCOPE_SYSTEM" << endl;
    }

    // 创建新线程
    // &thread: 用于存储新线程的标识符
    // NULL: 线程属性(使用默认属性)
    // PrintThread: 线程函数指针(新线程执行的函数)
    // (void *)param: 传递给线程函数的参数(将long转换为void*)
    result = pthread_create(&thread, &attr, PrintThread, (void *)param);

    // 检查线程创建是否成功
    if (result)  // rc != 0 表示创建失败
    {
        // pthread_create返回错误码(非零)
        // 通常应该处理错误,这里直接返回
        return 0;
    }

    result = pthread_attr_destroy(&attr);

    // 主线程继续执行自己的工作(与子线程并发执行)
    for(int i = 0; i < 5; i++){
        cout << "Main thread " << i << endl;  // 主线程输出
        sleep(2);  // 休眠2秒(子线程休眠1秒,所以子线程输出更频繁)
    }

    pthread_join(thread, NULL);

    return 0;
}
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐