线程创建、退出

创建线程实际上就是确定调用该线程函数的入口点,线程的创建采用函数 pthread_create。在线程创建以后,就开始运行相关的线程函数,在该函数运行完之后,线程就退出,这也是线程退出的一种方式。另一种线程退出的方式是使用函数 pthread_exit() 函数,这是线程主动退出行为。这里要注意的是,在使用线程函数时,不能随意使用exit退出函数进行出错处理,由于exit的作用是使调用进程终止,往往一个进程包括了多个线程,所以在线程中通常使用 pthread_exit 函数来代替进程中的退出函数exit

由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放。正如进程之间可以通过wait()函数系统调用来同步终止并释放资源一样,线程之间也有类似的机制,那就是 pthread_join 函数。pthread_join 函数可以用于将当前线程挂起,等待线程的结束。这个函数是一个线程阻塞函数,调用它的函数将一直等待直到被等待的线程结束为止,当函数返回时,被等待线程的资源被回收。

函数原型:

#include <pthread.h>

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

void pthread_exit(void *retval);

通常的形式为:

pthread_t pthid;

pthread_create(&pthid,NULL,pthfunc,NULL);    

pthread_create(&pthid,NULL,pthfunc,(void*)3);

pthread_exit(NULL);     

pthread_exit((void*)3);                                //3作为返回值被pthread_join函数捕获。

函数pthread_create用来创建线程。返回值:成功,则返回0;失败,则返回对应错误码各参数描述如下:

·参数thread是传出参数,保存新线程的标识

·参数attr是一个结构体指针,结构中的元素分别指定新线程的运行属性,attr可以用pthread_attr_init等函数设置各成员的值,但通常传入为NULL 即可;

·参数start_routine是一个函数指针指向新线程的入口点函数,线程入口点函数带有一个void *的参数由pthread_create的第4个参数传入

·参数arg用于传递给第3个参数指向的入口点函数的参数,可以为NULL,表示不传递

函数pthread_exit表示线程的退出。其参数可以被其它线程用pthread_join函数捕获。

1、在线程库里不能使用perror函数查看错误
2、能够perror的函数,函数失败以后,修改了全局变量 errno,perror读取error,显示错误
主线程退出,文件描述符关闭,进程地址空间清理

ps -elLf  查看线程
pthread_creat.c pthread_creat_val.c
#include<stdio.h>
#include<pthread.h>

void* threadfunc(void*p)
{
        printf("I am a child thread\n");
        while(1);
}
int main()
{
        pthread_t thdid;
        pthread_create(&thdid,NULL,threadfunc,NULL);
        while(1);
        return 0;
}
8B9cATWV1XyosAAAAASUVORK5CYII=
#include<stdio.h>
#include<pthread.h>

void* threadfunc(void*p)
{
        int i;
        i=(int)p;
        printf("I am a child thread %d\n",i);
        while(1);
}
int main()
{
        pthread_t thdid;
        pthread_create(&thdid,NULL,threadfunc,(void*)1);
        while(1);
        return 0;
}
BcdVd3QQBAAAAAAAAAAAAAADA52NG55ZwAAAAd8mnPBEMAABAPTAAAAAwUWAAAABgosAAAADARIEBAACAiQIDAAAAEwUGAAAAJgoMAAAATBQYAAAAmCgwAAAAMFFgAAAAYKLAAAAAwESBAQAAgIkCAwAAABMFBgAAACYKDAAAAEwUGAAAAJgoMAAAADBRYAAAAAAAAAAAAAAAAAAAgPvkfzd4Zeq0dWFGAAAAAElFTkSuQmCC


BzgB8qHPFS+cAAAAAElFTkSuQmCC    //进程相同,所以父进程也相同(4961),但是线程号不相同 5100、5101

然后  cd /proc , proc下面每一个文件夹都是一个进程: 
bjGMQeWMjOAAAAAASUVORK5CYII=

//进入我们运行的进程的文件夹,5100,里面都是进程资源,这就是为什么复制进程这么慢,它里面的资源都要复制一份,线程则不同,它共享这些东西,只有task里面的东西是自己独有的
DznBg6QX7qUXAAAAAElFTkSuQmCC   JPYL9vxpfuG7DiwbeWUZZJTdV4uU5WiXBbTXoJQLpb+UsYd7+e+rCjvEtlAqN8wRVFOzP8BWC7m+ncwWB4AAAAASUVORK5CYII=  //这里面就是我们的线程


ps -elLf  查看线程   编译加上 -lpthread

(uname -m)  查看ubuntu版本是多少位的

(cd  /proc)里面存储的都是进程,然后cd到刚才程序的进程号文件夹(cd 进程),在进入task查看线程

pthread_creat_arg1.c
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
void *thread_func(void *p)
{
        strcpy((char*)p,"hello,world!");
        printf("I am child thread  , p's address = %p\n",p);
        printf("child thread p=%s\n",(char*)p);
        return 0;
}
int main(void)
{
        pthread_t pt_id;
        void *p = malloc(20*sizeof(char));
        pthread_create(&pt_id,NULL,thread_func,p);
        printf("p's address = %p\n",p);   //%p 打印指针地址
        sleep(2);
        printf("main thread , p=%s\n",(char*)p);
        return 0;
}
// %p
Bzzfin5Oz69kAAAAAElFTkSuQmCC

// %x
XfUld71nakAAAAAAAAAAAAAYAT+HyJL5o3eIQpgAAAAAElFTkSuQmCC



pthread_exit.c
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>

void* threadfunc(void*p)
{
        strcpy((char*)p,"hello");
        printf("I am a child thread %s\n",(char*)p);
        printf("child p is %x\n",p);
        pthread_exit((void*)0);     //退出值是0,就可以直接写NULL,表示没有返回值
}
int main()
{
        pthread_t thdid;
        void* p=malloc(20);
        printf("p is %x\n",p);
        printf("I am a father thread %s\n",(char*)p);   //线程共享资源,这里字符串打印的是空的
        int ret = pthread_create(&thdid,NULL,threadfunc,p);
        if(ret!=0)
        {
                printf("error pthread_create\n");
                return -1;
        }
        sleep(1);
        printf("I am a father thread after sleep %s\n",(char*)p);   
        return 0;
}
wNPWHijYr3wlwAAAABJRU5ErkJggg==

退出,返回一个整数,要在主线程用函数拿到这个整数



2. 线程的等待退出

等待线程退出:

            线程从入口点函数自然返回,或者主动调用pthread_exit()函数,都可以让线程正常终止。

            线程从入口点函数自然返回时,函数返回值可以被其它线程用pthread_join函数获取。


pthread_join原型为:

       #include <pthread.h>

   int pthread_join(pthread_t th, void **thread_return);


1.该函数是一个阻塞函数一直等到参数 th 指定的线程返回与多进程中的waitwaitpid类似。

thread_return是一个传出参数,接收线程函数的返回值。如果线程通过调用pthread_exit()终止,则 pthread_exit() 中的参数相当于自然返回值,照样可以被其它线程用pthread_join()获取到


2.thid传递0值时,join返回ESRCH错误。




//创建线程,通过pthread_join拿到我们的线程的返回值
pthread_exit(int).c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void* thread(void* p)
        strcpy((char*)p,"hello");
        printf("I am child thread\n");
        printf("child p is %p\n",p);
        pthread_exit((void*)5);              //通过pthread_exit实现线程退出,没有返回值,就写pthread_exit(NULL);
}

int main()
{
        pthread_t th_id;
        void* p=malloc(20);
        printf("p is %p\n",p);
        int ret=pthread_create(&th_id,NULL,thread,p);           //创建线程,将数值放入指针内
        if(ret!=0)
        {
                printf("pthread_create failed ret=%d\n",ret);
                return -1;
        }
        int i;        
        //void *i;      //申请了一块内存,void *,到时候把这个传给下面函数,函数操作会给你这块内存自己定好偏移,附上值,也就是这块地址开始的内存里就存的是上面退出的5;所以最后能直接(int)i;
        ret=pthread_join(th_id,(void**)&i);     //函数规定第二个形参要是一个void**,i来接数据,所以必须取地址
//要用 i 来接返回值,也就是要改变 i 所以必须取地址,但是取完一次地址就不能再取地址,最后转成(void**);
        if(ret!=0)
        {
                printf("pthread_join failed ret=%d\n",ret);
                return -1;
        }
        printf("main thread %s\n",(char*)p);
        printf("main thread i=%d\n",i);
        //printf("main thread i=%d\n",(int)((int*)i));
        //printf("main thread i=%d\n",(int)i);
        return 0;
}
AdLOaJlMqmJvAAAAAElFTkSuQmCC


void* 表示拿一个地址,所有地址都可以默认转void*,但是如果拿到地址要进行操作,就必须转成对应类型的指针,因为它要知道偏移量

//创建线程,子线程结束后,malloc内存依然能够使用
pthread_malloc.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void* thread(void* p)
        p=malloc(20);
        strcpy((char*)p,"hello");
        printf("I am child thread\n");
        printf("child p is %p\n",p);
        return p;
}

int main()
{
        pthread_t th_id;
        int ret=pthread_create(&th_id,NULL,thread,NULL); //创建线程,将数值放入指针内
        if(ret!=0)
        {
                printf("pthread_create failed ret=%d\n",ret);
                return -1;
        }
        char* p;                  //void* p;
        ret=pthread_join(th_id,(void**)&p);          //要改变p所存的地址,所以&p
        if(ret!=0)
        {
                printf("pthread_join failed ret=%d\n",ret);
                return -1;
        }
        printf("p = %p\n",p);
        printf("p = %s\n",p);        //(char*)p
        return 0;
}
g+PKsFf82IV4wAAAABJRU5ErkJggg==


转载于:https://www.cnblogs.com/meihao1203/p/8503726.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值