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

函数可以有返回值,那么线程作为一个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库可以创建、同步和销毁线程。头文件是

1.2 C语言线程创建

1.2.1 步骤

        (1)包含头文件 #include

        (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 
#include 
#include 

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 
#include 
#include 

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++中,可以使用头文件中的函数来创建和管理线程。以下是一个简单的示例代码:

#include 
#include 

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 
#include 


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 
#include 


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

        运行结果:

2.2.3 成员函数

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

#include 
#include 


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 
#include 


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 
#include 

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

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

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

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

#include 
#include 
#include 

 
void func2(int x, int y,std::promise &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 promiseObj;
  //将future和promise关联
  std::future 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 promiseObj2;
  std::future 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的值,本质上也是一种共享指针的方式。

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

你可能感兴趣的:(C/C++精进之路,c++,多线程,返回值,数据结构)