C++面向对象(OOP)编程-线程返回值

2023-12-28 14:25:19

函数可以有返回值,那么线程作为一个handler是如何返回值的呢?在C语言中线程可以直接返回值,然后通过thread.join(返回值)来获取,但是C++不支持这样做,C++中是怎么返回线程的返回值的呢?本文将会比较详细的介绍C语言线程的返回值,以及几种C++线程替代返回值的方法。

🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:C/C++精进之路
🎀CSDN主页?发狂的小花
🌄人生秘诀:学习的本质就是极致重复!

目录

1 C语言线程

1.1?pthread

1.2 C语言线程

1.2.1 步骤

1.2.2?pthread_create参数说明

1.2.3 pthread_join参数说明

1.3 C语言线程返回值

2 C++线程

2.1 thread

2.2 C++线程调用参数种类

2.2.1 函数指针

2.2.2?Lambda表达式

2.2.3?成员函数

2.2.4 函数对象

2.3?C++线程返回值

2.3.1 共享指针

2.3.2 future和promise配合实现


1 C语言线程

1.1?pthread

????????在C语言中,可以使用POSIX线程库(pthread)来实现多线程编程。使用pthread库可以创建、同步和销毁线程。头文件是<pthread.h> 。

1.2 C语言线程

1.2.1 步骤

? ? ? ? (1)包含头文件?#include <pthread.h>

????????(2)申请线程对象,pthread_t thread1;

? ? ? ? (3)创建线程 pthread_create(&thread1,NULL,handler,&in);

1.2.2?pthread_create参数说明

? ? ? ? ? ? ? ? 参数说明:

? ? ? ? ? ? ? ? 第一个参数:thread1为线程对象地址

? ? ? ? ? ? ? ? 第二个参数:线程属性,pthread 线程属性包括:

? ? ? ? ? ? ? ? ? ? ? ? (1)调度策略,

? ? ? ? ? ? ? ? ? ? ? ? (2)调度的优先级,

? ? ? ? ? ? ? ? ? ? ? ? (3)线程的分离状态(分离线程:主动结束 和 可汇合线程:等待原有创建线程结束 ? ? ? ? ? ? ? ? ? ? ? ?才结束,即pthread_ioin()调用后,该子线程结束),

? ? ? ? ? ? ? ? ? ? ? ? (4)线程ID

? ? ? ? ? ? ? ? ? ? ? ? (5) 线程的继承性?

? ? ? ? ? ? ? ? 第三个参数:线程handler处理函数

? ? ? ? ? ? ? ? ? ? ? ? 一般定义为 void * handler(void *data){}; 如果需要返回值,可以申请堆空间返回

? ? ? ? ? ? ? ? ? ? ? ? pthread_join(thread_id,void * (ret)); void *ret是返回值的地址,可以用来得到返回

? ? ? ? ? ? ? ? ? ? ? ? 值的地址?

? ? ? ? ? ? ? ? 第四个参数: ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? 线程处理函数的输入参数,用来传参给处理函数 ?

1.2.3 pthread_join参数说明

? ? ? ? pthread_join(argv1,argv2);?

? ? ? ? ? ? ? ? 参数说明:

? ? ? ? ? ? ? ? ? ? ? ? argv1 为线程对象

? ? ? ? ? ? ? ? ? ? ? ? argv2 这里传入的二维指针,指的是存储返回值地址的指针的地址

????????

以下是一个简单的示例代码:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

void *print_hello(void *arg) {
    printf("Hello from thread %ld\n", (long)arg);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    int rc1, rc2;
    long t1 = 1, t2 = 2;

    /* Create independent threads each of which will execute function */
    rc1 = pthread_create(&thread1, NULL, print_hello, (void *)t1);
    if (rc1) {
        fprintf(stderr, "Error: Unable to create thread %d", rc1);
        exit(-1);
    }
    rc2 = pthread_create(&thread2, NULL, print_hello, (void *)t2);
    if (rc2) {
        fprintf(stderr, "Error: Unable to create thread %d", rc2);
        exit(-1);
    }

    /* Wait till threads are complete before main continues. */
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

? ? ? ? 运行结果:

????????

1.3 C语言线程返回值

如下实现了线程返回值:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

void * add1_handler(void *arg)
{
    int *ret = (int*)malloc(sizeof(int));

    *ret = *((int*)arg) + 1;
    return ret;
}

int main() {
    pthread_t thread1;
    int in = 34;
    int rc1 = 0;
    /* Create independent threads each of which will execute function */
    rc1 = pthread_create(&thread1, NULL, add1_handler, (void*)&in);
    if (rc1) {
        fprintf(stderr, "Error: Unable to create thread %d", rc1);
        exit(-1);
    }
    /* Wait till threads are complete before main continues. */

    int *ret_value = NULL;
    pthread_join(thread1, (void**)(&ret_value));

    printf("最终的结果: %d \n",*ret_value);
    
    free(ret_value);

    return 0;
}

? ? ? ? 运行结果:

最终的结果: 35

2 C++线程

2.1 thread

C++线程是一种轻量级的执行单元,可以在单个程序中并发执行多个任务。C++标准库提供了对线程的支持,包括创建、同步和销毁线程等功能。

在C++中,可以使用<thread>头文件中的函数来创建和管理线程。以下是一个简单的示例代码:

#include <iostream>
#include <thread>

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

int main() {
    // 创建一个新线程并执行print_hello函数
    std::thread t(print_hello);

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

    return 0;
}

? ? ? ? 运行结果:

2.2 C++线程调用参数种类

2.2.1 函数指针

可以将函数指针作为参数传递给std::thread类来定义线程。

#include <iostream>
#include <thread>


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

int main() {
    std::thread t(&print_hello); // 使用函数指针定义线程
    t.join();
    return 0;
}

? ? ? ? 运行结果:

2.2.2?Lambda表达式

可以使用Lambda表达式来定义线程。

#include <iostream>
#include <thread>


int main() {
    std::thread t([]{
        std::cout << "Hello from thread!" << std::endl;
    }); // 使用Lambda表达式定义线程
    t.join();
    return 0;
}

? ? ? ? 运行结果:

2.2.3?成员函数

可以将成员函数作为参数传递给std::thread类来定义线程。

#include <iostream>
#include <thread>


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

int main() {
    MyClass obj;
    std::thread t(&MyClass::print_hello, &obj); // 使用成员函数定义线程
    t.join();
    return 0;
}

? ? ? ? 运行结果:

? ? ? ? 上述代码使用成员函数作为线程的handler,并把实例传入,以达到调用某一对象的成员函数。

2.2.4 函数对象

可以将函数对象作为参数传递给std::thread类来定义线程。函数对象需要重载operator()运算符。

#include <iostream>
#include <thread>


class MyFunctor {
public:
    void operator()() {
        std::cout << "Hello from thread!" << std::endl;
    }
};

int main() {
    MyFunctor functor;
    std::thread t(functor); // 使用函数对象定义线程
    t.join();
    return 0;
}

? ? ? ? 运行结果:

? ? ? ?

? ? ? ? 上述代码通过运算符()重载实现用函数对象完成线程的参数。

2.3?C++线程返回值

????????由于C++线程的join不支持接收参数,因此不可以通过这种方式返回值,只能通过传入共享指针或者对象,以及使用future和promise来实现线程返回值。

2.3.1 共享指针

? ? ? ? 本质上传递变量、对象等都是共享指针。

#include <iostream>
#include <thread>

using namespace std;

void * add1_handler(void *arg)
{
    *(int*)arg = 56;
    
}

int main() {
    
    int value = 11;

    std::cout << "执行前value: " << value << std::endl;
    std::thread t(&add1_handler,&value);
    // 等待线程执行完成
    t.join();

    std::cout << "执行后value: " << value << std::endl;

    return 0;
}

? ? ? ? 运行结果:

执行前value: 11
执行后value: 56

2.3.2 future和promise配合实现

????????std::future和std::promise是封装好的两个类模板,这两个类需要配合使用,他们的头文件是#include <future>

????????std::future,它表示存储着一个未来会被初始化的变量。这个变量可以通过std::future提供的成员函数std::future::get()来得到。如果在这个变量被赋值之前就有别的线程试图通过std::future::get()获取这个变量,那么这个线程将会被阻塞到这个变量可以获取为止。

????????std::promise同样也是一个类模板,这个对象承诺在未来一定会初始化一个变量(这个变量也就是std::future中的变量)。

????????每一个std::promise对象都有一个与之关联的std::future对象。当std::promise设置值的时候,这个值就会赋给std::future中的对象了。

#include <iostream>
#include <future>
#include <thread>

 
void func2(int x, int y,std::promise<int> &promiseObj) {
  promiseObj.set_value(x+y);
}
 
int main()
{
  //计算(a+b)/(x+y)
  //用三个线程,一个线程计算a+b,另一个线程计算x+y
  int a, b, x, y;
  a = 10, b = 8, x = 2, y = 4;
 
  int sum1, sum2;
  //声明一个类
  std::promise<int> promiseObj;
  //将future和promise关联
  std::future<int> futureObj = promiseObj.get_future();
  //模板传参的时候使用ref,否则传参失败
  std::thread t1(func2, a, b, ref(promiseObj));
  t1.join();
  //获取值
  sum1 = futureObj.get();
  std::cout << "sum1=" << sum1 << std::endl;
 
  //不能直接复用上面的future和promise
  std::promise<int> promiseObj2;
  std::future<int> futureObj2 = promiseObj2.get_future();
 
  std::thread t2(func2, x, y, ref(promiseObj2));
  t2.join();
  sum2 = futureObj2.get();
  std::cout << "sum2=" << sum2 << std::endl;
 
  std::cout << "sum1/sum2=" << sum1 / sum2 << std::endl;
   
  return 0;
}

? ? ? ?运行结果:

sum1=18
sum2=6
sum1/sum2=3

? ? ? ? 分析结果可知,上述代码实现了线程返回值,通过将一个promise对象绑定到一个future上,通过传入promise对象作为线程的返回值,最终由future获取promise的值,本质上也是一种共享指针的方式。

🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏?→关注🔍
感谢大家的观看和支持!最后,?祝愿大家每天有钱赚!!!

文章来源:https://blog.csdn.net/m0_47324800/article/details/135260916
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。