c语言怎么创建线程和使用

c语言怎么创建线程和使用,第1张

1、添加线程相关的头文件:#include<pthread.h>

2、线程创建函数是pthread_create()函数,该函数的原型为:

int pthread_create(pthread_t *thread,pthread_attr_t *attr,void* (*start_routine)(void*),void *arg)

3、线程退出函数是pthread_exit()函数,该函数的原型为:

void pthread_exit(void *retval)

创建线程的示例程序如下:

/*

**程序说明:创建线程函数pthread_create()函数的使用。

*/

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

//打印标识符的函数

void print_ids(const char *str)

{

pid_t pid //进程标识符

pthread_t tid //线程标识符

pid=getpid() //获得进程号

tid=pthread_self() //获得线程号

printf("%s pid:%u tid:%u (0x%x)\n",

str,(unsigned int)pid,(unsigned int)tid,(unsigned int)tid) //打印进程号和线程号

}

//线程函数

void* pthread_func(void *arg)

{

print_ids("new thread:") //打印新建线程号

return ((void*)0)

}

//主函数

int main()

{

int err

pthread_t ntid //线程号

err=pthread_create(&ntid,NULL,pthread_func,NULL) //创建一个线程

if(err != 0)

{

printf("create thread failed:%s\n",strerror(err))

exit(-1)

}

print_ids("main thread:") //打印主线程号

sleep(2)

return 0

}

包含头文件 #include <thread>

1、std::thread 的使用非常放便和强大,该类几乎可以把任何函数作为线程主函数。

2、用法:

    首先包含头文件 #include <thread>

    定义线程主函数: 根据不同的需要,线程的主函数可以是普通函数、函数对象、lambda表达式或者类成员函数。

    建立std::thread对象,并把线程要运行的函数(线程主函数)以及相应的函数参数通过构造函数传递给该对象, 构造函数通常会海纳百川。

例程:

#include <thread>

#include <iostream>

class ThreadMain {

public:

    void operator()() {

        run()

    }

    void run() {

        std::cout << "Hello, C++11 thread\n"

    }

}

void generalFunc(int data) {

    std::cout << "Hello, C++11 thread\n"

}

int main() {

    ThreadMain tm

    std::thread t1(generalFunc, 1)        /*传递普通函数指针和参数0给thread对象t1*/

    std::thread t2(&ThreadMain::run, &tm)   /*将成员函数传递给thread对象t2, 并且传递调用该函数的对象的指针&tm*/

    std::thread t3(tm)     /*传递一个函数对象给t3*/

    std::thread t4([]() { std::cout << "Hello, C++11 thread\n" }) /*传递lambda表达式给thread对象t4*/

    /* 调用join函数等待线程终止,并回收线程所占资源*/

    t1.join()

    t2.join()

    t3.join()

    t4.join()

}

这是 *** 作系统的两个定义,进程好比一个任务,假设你要做一道菜,家里啥原料甚至盐都没有,于是就要买菜->买作料->做菜。这个任务就是可以理解为一个进程。你可以派一个人去买菜买盐回来再做菜,你也可以派两个人一个买盐一个买菜,这里的人好比线程。进程就是线程的容器。

任何程序执行都会有一个主线程,在c++中就是主函数所在的线程,那么其他线程也需要一个函数去执行,不然其他线程鬼知道自己要干什么。

这里我创建了俩函数,分别打印两句话。

接下来就是创建线程,首先我们引入thread这个头文件,然后创建一个thread对象,构造函数参数为咱们的两个线程函数。我们用join()函数表示等待,咱们先试试效果。

最后我们需要定义主线程和这俩线程的关系,因为有时候主线程跑得快,那么主线程就结束了而这俩蜗牛还在搞,那么就会有一系列问题。一般建议让主线程等待这俩货搞完了在结束保证安全,当然也可以自己先跑路。

首先打印线程1开始,接下来本应该打印换行符的,结果让线程2开始抢了先。这是因为这俩线程相互没什么关系,谁快谁慢看电脑心情。最后所有线程退出,主线程就可以结束啦。

这次运行的是join,那么我试试主线程不等待这俩货,为了演示更加清晰,我删除了一个货,留下线程1,再把线程1要干的活加重一点。

打印了什么玩意儿,主线程结束先打,之后换行都没有就线程1开始,然后换了行(也不知道几行),然后啥也没了。为了看得更清楚,我加大了主函数的工作量。

咱不用细讲了,结果就是这样,如果线程先退出,大舅不打印了,但是不代表其他线程就不干活了,活还是在干的。

这里的detach()其实会有很多问题,那就是之后传参的问题,线程函数的参数在创建thread对象时一起传进去。

这里传递了俩参数,一个是int类型,另一个是string引用,还有一个就是指针。之前说过,如果我们用detach,主线程会被回收,那么这里的两个参数会不会被回收,如果回收了,次线程不就没有参数了吗,尤其是这里的string引用和指针。我们探究一下。我们先来一把join看看这两种变量的地址关系。分别打印三个对象的地址

三个变量,只有指所指的对象的地址是相同的。引用的地址居然不同,可见拷贝了,那么在进一步探究,我们自定义类,在拷贝构造函数里打印东西。

我们在三中构造函数里都打印东西,并且输出自定义类对象地址。

发现咱们使用引用是发生了拷贝,那么不用引用呢,其实会发生两次拷贝。如下图

会发现隐式转换是在子线程里干的活,那就危险了。

现在如果执意要使用引用,但是都不能复制,比如多个线程需要 *** 作主线程里同一个对象,指针是一种形式,引用当然也可以,在std空间里,有个函数叫ref(),用它包起来的对象就是真引用,不会发生复制,形参里的const修饰符也可以不用了。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/6062674.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-13
下一篇 2023-03-13

发表评论

登录后才能评论

评论列表(0条)

保存