C++创建多线程的方法(根据系统或者项目可选择多种方法)

 原文链接:C++创建多线程的方法总结_C 语言_脚本之家

C++中的多线程方法:std、boost、pthread、windows api等;每个库都有自己的线程封装和设计方式。

一、C++11 std::thread 

优点:原先使用多线程只能用系统的API无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改。现在在C++11中只需使用语言层面的thread可以解决这个问题

缺点:

  1. 编译器兼容性‌:使用C++11特性需要编译器支持,特别是gcc编译器版本需要大于4.8,并且在编译时需要加上参数-std=c++11 -lpthread。这意味着,在一些较旧的编译环境中,开发者可能无法使用std::thread,或者需要更新编译器和编译参数,这增加了使用的门槛‌1。

  2. 学习成本‌:多线程编程本身具有一定的学习曲线,std::thread的引入虽然简化了多线程的使用,但对于初学者来说,仍然需要一定的时间来理解和掌握。此外,与操作系统提供的线程接口(如pthread)相比,std::thread虽然更方便,但在某些特定场景下,pthread可能提供更细粒度的控制‌2。

  3. 项目需求‌:并非所有项目都需要多线程编程。对于一些小型项目或者简单的任务分配,使用多线程可能并不必要,因此std::thread在这些场景下自然不会被采用。而对于需要高性能计算或者并发处理的大型项目,虽然std::thread是一个不错的选择,但项目的其他需求和技术栈可能会限制其使用‌。

1.1 创建线程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include <iostream>

#include <thread>

  

void foo()

{

    std::cout << "Hello from thread" << std::endl;

}

  

int main()

{

    std::thread t1(foo);

    t1.join();

  

    return 0;

}

在上面的代码中,通过 std::thread t1(foo) 创建了一个新线程,并在新线程中执行了函数 foo。 

1.2 线程管理

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <thread>

  

void foo()

{

    std::cout << "Hello from thread" << std::endl;

}

  

int main()

{

    std::thread t1(foo);

    t1.join();

    t1.detach();

  

    return 0;

}

在上面的代码中,通过调用 t1.join() 可以等待线程 t1 结束,并通过调用 t1.detach() 可以分离线程 t1,使线程在后台运行。 

std::thread::detach() 方法是分离线程的方法,通过调用 detach() 方法,可以让线程在后台独立运行,不需要等待线程结束即可返回。与调用 join() 方法不同,分离的线程不受父线程的控制,因此如果父线程结束,分离的线程不会因此结束。请注意,分离的线程一旦开始执行,它将独立运行,不受任何控制,因此不能在父线程中等待它的结束或者通过其他方式获取其结果。如果需要等待线程结束,请使用 join() 方法。

分离线程的主要作用是让线程在后台独立运行,不需要等待线程结束即可返回。这样可以在不需要等待线程结束的情况下,在父线程中执行其他任务,从而提高程序的效率。

1.3 传递参数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include <iostream>

#include <thread>

  

void foo(int x)

{

    std::cout << "Hello from thread, x = " << x << std::endl;

}

  

int main()

{

    std::thread t1(foo, 10);

    t1.join();

  

    return 0;

}

在上面的代码中,通过在创建线程时传递参数 10,并在函数 foo 中读取参数,实现了在线程中传递参数的功能。

1.4 线程间通信 

1.4.1 使用共享变量和互斥量(互斥锁):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

#include <iostream>

#include <thread>

#include <mutex>

  

int g_num = 0;

std::mutex g_num_mutex;

  

void print_num() {

    while (true) {

        g_num_mutex.lock();

        if (g_num >= 100) {

            g_num_mutex.unlock();

            break;

        }

        std::cout << "Thread " << std::this_thread::get_id() << ": " << g_num++ << std::endl;

        g_num_mutex.unlock();

    }

}

  

int main() {

    std::thread t1(print_num);

    std::thread t2(print_num);

  

    t1.join();

    t2.join();

  

    return 0;

}

我们定义了一个全局变量g_num,两个线程分别运行print_num函数。print_num函数不断地对g_num变量进行读写操作,并使用互斥量g_num_mutex对该变量进行加锁。这样可以确保在每次读写操作时,不会有其他线程访问g_num变量。如果g_num的值已经大于等于100,则表示线程退出。最后主线程调用join函数,等待其他线程退出。

1.4.2 使用共享内存

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

#include <iostream>

#include <thread>

#include <string>

  

using namespace std;

  

string message;

  

void write_message()

{

    message = "Hello World";

}

  

void read_message()

{

    cout << message << endl;

}

  

int main()

{

    thread t1(write_message);

    thread t2(read_message);

  

    t1.join();

    t2.join();

  

    return 0;

}

1.5 其他线程相关信息

  • std::thread::hardware_concurrency():返回当前系统支持的最大线程数。
  • std::thread::native_handle():返回线程的原生句柄,在不同的平台中可能不同。
  • std::thread::joinable():判断线程是否可以被 join,如果线程已经结束或者被分离,则返回 false。
  • std::thread::join():等待线程结束,直到线程结束才返回。
  • std::thread::detach():分离线程,使线程可以在后台运行,并且不需要等待其结束。
  • std::thread::get_id() :返回线程ID。

二、boost多线程库

Boost Thread库是跨平台的,它可以在不同的操作系统上运行,包括Windows、Linux、Mac等。这是因为Boost库的设计考虑了跨平台兼容性,使得开发者能够在不同的操作系统上使用相同的代码基础来实现多线程编程。Boost Thread库通过封装底层操作系统的线程API,提供了一组统一的接口,使得开发者可以更容易地编写多线程程序,而无需关心底层操作系统的差异。这种跨平台的设计使得Boost Thread库成为了一个广泛使用的多线程解决。

官方文档:

Chapter 38. Thread 4.8.0 - 1.73.0

Boost 库中的 boost::thread 类可以方便地创建和管理多线程。以下是一个使用 Boost 库中的 boost::thread 类创建多线程的简单示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <boost/thread.hpp>

  

void worker_thread()

{

    std::cout << "Worker thread is running" << std::endl;

}

  

int main()

{

    boost::thread worker(worker_thread);

    std::cout << "Main thread is running" << std::endl;

    worker.join();

  

    return 0;

}

三、POSIX线程(Linux&Unix) 

Pthreads最初是为Unix-like系统设计的(系统的API),如Linux和Solaris,但也有在Windows上实现的版本,如pthreads-w32

C++ POSIX 线程(pthread)库可以帮助您在 C++ 中创建和管理多线程。下面是一个创建和启动一个新线程的示例代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

#include <pthread.h>

#include <iostream>

  

void *thread_func(void *arg)

{

    std::cout << "Thread started with argument: " << *((int *)arg) << std::endl;

    return NULL;

}

  

int main()

{

    pthread_t thread_id;

    int arg = 42;

  

    // 创建新线程

    int result = pthread_create(&thread_id, NULL, thread_func, &arg);

    if (result != 0) {

        std::cerr << "Error: pthread_create() failed" << std::endl;

        return 1;

    }

  

    // 等待线程结束

    result = pthread_join(thread_id, NULL);

    if (result != 0) {

        std::cerr << "Error: pthread_join() failed" << std::endl;

        return 1;

    }

  

    return 0;

}

这段代码中,pthread_create 函数用于创建一个新线程,并启动它。第一个参数是一个指向线程 ID 的指针,第二个参数指定了线程的属性,通常为 NULL,第三个参数是线程函数的地址,最后一个参数是传递给线程函数的参数。

pthread_join 函数等待线程结束,第一个参数是线程 ID,第二个参数是接收线程返回值的指针,通常为 NULL

四、 Windows线程库

4.1 线程使用

下面是使用Windows API创建线程并打印数字并获取重要的线程信息的代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

#include <iostream>

#include <Windows.h>

  

DWORD WINAPI ThreadFunction(LPVOID lpParam)

{

    // 获取当前线程ID

    DWORD threadId = GetCurrentThreadId();

    std::cout << "Thread ID: " << threadId << std::endl;

  

    // 获取线程传入的参数

    int threadParam = *(int*)lpParam;

    for (int i = 0; i < threadParam; i++)

    {

        std::cout << i << std::endl;

    }

    return 0;

}

  

int main()

{

    int num = 10;

  

    // 创建线程

    HANDLE hThread = CreateThread(NULL, 0, ThreadFunction, &num, 0, NULL);

  

    // 等待线程结束

    WaitForSingleObject(hThread, INFINITE);

  

    // 关闭线程句柄

    CloseHandle(hThread);

  

    return 0;

}

4.2 线程通信

在 Windows API 中,可以使用 CreateThread 函数创建线程,以下是通过共享变量实现线程间通信的代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#include <Windows.h>

#include <iostream>

  

DWORD WINAPI ThreadFunction1(LPVOID lpParam)

{

    int* sharedVariable = (int*)lpParam;

    while (true)

    {

        if (*sharedVariable == 0)

        {

            std::cout << "Thread 1: sharedVariable = " << *sharedVariable << std::endl;

            *sharedVariable = 1;

        }

    }

    return 0;

}

  

DWORD WINAPI ThreadFunction2(LPVOID lpParam)

{

    int* sharedVariable = (int*)lpParam;

    while (true)

    {

        if (*sharedVariable == 1)

        {

            std::cout << "Thread 2: sharedVariable = " << *sharedVariable << std::endl;

            *sharedVariable = 0;

        }

    }

    return 0;

}

  

int main()

{

    int sharedVariable = 0;

    HANDLE hThread1 = CreateThread(NULL, 0, ThreadFunction1, &sharedVariable, 0, NULL);

    HANDLE hThread2 = CreateThread(NULL, 0, ThreadFunction2, &sharedVariable, 0, NULL);

    WaitForMultipleObjects(2, &hThread1, TRUE, INFINITE);

    CloseHandle(hThread1);

    CloseHandle(hThread2);

    return 0;

}

在主函数中,我们调用了 CreateThread 函数创建了两个线程,将共享变量 sharedVariable 的地址作为参数传入。线程 1 和线程 2 都通过判断共享变量的值来实现通信,它们每当共享变量的值变化时都会输出当前的值。  

在这个例子中,WaitForMultipleObjects函数将等待两个线程hThread1和hThread2完成,并且要求等待所有事件对象完成,因此参数bWaitAll的值为TRUE。并且dwMilliseconds的值为INFINITE,所以等待时间是无限的。

以上:原文链接:C++创建多线程的方法总结_C 语言_脚本之家

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值