linux多线程相关的API-(1)--创建/退出/加入/分离等

注意:多线程相关的代码,在编译时必须加-lpthread或者-pthread选项,例如:

gcc thread_test.c  -o test_exe  -pthread

 

一、创建线程:pthread_create

原型:

int pthread_create(pthread_t *tid,
                    const pthread_attr_t *attr,
                    (void*)(*start_rtn)(void* arg),
                    void *arg);

形参:tid输出所成功创建的新线程的线程ID,tid=thread id;

attr设定所创建的线程参数,传入NULL意味着使用默认参数;

start_rtn线程入口函数,函数格式形如: void *thread_entry(void *para);

arg创建新线程时,要传给入口函数的参数;

 

注意:通过本函数把参数arg传给新线程时,是需要一定时间的(确切的说,是创建线程这一过程较为耗时),那么从执行完本函数开始,一直到新线程被创建完成,且新线程读完arg参数之前,主线程中实参arg指向的内容不允许变,否则,新线程读到的启动参数就不对了,这一问题主要出现在类似这种代码中:

pthread_t  tid[5];
for( i = 0; i < 5; i++)
{
    stat = pthread_create(&tid[i], NULL, test_func, &i);
    ````//其余代码
}

感觉上,创建的5个线程,会在各自的入口函数中,依次收到pthread_create的第4个实参:0、1、2、3、4,而实际上,这5个线程收到的却都是5,原因就在于,进程尚未读到这个第四实参,i的值就被改变了。
这一问题一般有3个解决方法:
① 本函数返回后,sleep一段时间,目的是线程创建完毕,且读完arg参数,
② 为每一个线程用不同的变量传递参数,而不是跟这个例子似的,用同一个变量i;
③ 这种方法仅适用于传递的数据的字节数≤sizeof(指针)时,换句话说就是,本来传参是通过传递个地址给线程,让线程从这个地址中读出真正的参数,显然,这也是引发上述问题的根源,这个地址处的值可能会改变。但是,pthread_create传递的第4实参,指针本身的值不会变,也即,我们可以投机取巧,把这个指针本身的值作为参数传给新线程,这个值无论如何不会出错的。也即,在线程入口函数void* start_rtn(void* arg)中,读*arg的值可能会变,*arg的值可能会被主线程给修改,但是arg本身的值,是不会变的。

二、线程退出:pthread_exit

原型:void pthread_exit(void* retval);

功能:立即退出线程,如果退出时还想返回一些数据供父线程处理/使用,那么这些数据可以通过函数形参retval传出,传出的值可通过pthread_join函数获得。

注意:

1、我们传出的是数据的地址,而不是数据本身,因此数据本身必须是静态的(如果多个线程都用同一个入口函数,这方法就不行了)、或者从内存堆动态分配的,而决不能是函数中的动态临时变量,因为一旦线程入口函数返回,那么栈中的数据值就消失/不可用了

2、在线程的入口函数中执行return p;和执行pthread_exit(p);相同点是:都可以退出线程,都可以传出返回值,而且返回值都可以被pthread_join捕获。

区别在于:return p只能在入口函数中退出线程,而pthread_exit(p)可以在入口函数的子函数中退出线程;return p不会触发线程清理工作,pthread_exit(p)可以触发线程清理工作,详情请参考另一篇博文:线程取消与清理。

三、阻塞地等待某个线程退出pthread_join

原型:int pthread_join(pthread_t tid, void **retval);

功能:阻塞地等待某个线程退出,另外注意:父线程创建子线程之后,父线程会维护一些子线程的信息,只有显式地调用了该函数,父进程才会在子线程结束后清理所维护的子线程信息,换句话说,如果父线程不调用该函数,那么大量的子线程信息得不到释放,可能会造成堆溢出,除非:我们把创建的子线程与父线程分离开,这样子线程的信息在子线程结束后自动释放,分离线程所用的函数为:pthread_detach(pthread_t tid);

形参:tid 要等待的线程id;

retval为线程退出时,传出的值的指针的指针

//编译:gcc thread_basic.c -o test_exe -pthread
#include <limits.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

void *thread_entry(void* arg)
{
        int arg_val =  *(int*)arg;
        printf("child thread start with para: %d\n", arg_val);

        int *p_out = malloc(sizeof(int));//申请的空间用于传出线程的退出值
        //static int data_out = 0;
        //int *p_out = &data_out;//局部静态空间也可用来传出退出值
        *p_out = arg_val + 1;
        pthread_exit(p_out); //在入口函数中,本行代码等价于 return p_out;
        return p_out;//这一行实际上执行不到,线程已经被pthread_exit给退出了
}

int main()
{
        int status;//线程操作函数的返回值
        pthread_t  tid;//子线程ID
        int arg = 2;//传给子线程入口函数的实参
        int *p_recv_out;//pthread_join接收子线程的返回值

        //创建子线程
        status = pthread_create(&tid, NULL, thread_entry, &arg);
        if(0 == status)
        {
                printf("creat thread ok, tid = %ld\n", tid);
        }
        else
        {
                printf("creat thread failed, error info: %s\n", strerror(errno));
                return -1;
        }

        //等待子线程结束,并接收子线程的结束值
        status = pthread_join(tid, (void**)&p_recv_out);
         if(0 == status)
         {
                printf("child thread quit normally\n");
                printf("parent thread received exit data: %d\n", *p_recv_out);
                free(p_rec

运行结果:

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值