Linux多线程之创建、终止、等待和分离

线程创建函数:

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);
参数
thread:返回线程ID。
attr:设置线程的属性,attr为NULL表⽰示使⽤用默认属性。
start_routine:是个函数地址,线程启动后要执⾏行的函数。
arg:传给线程启动函数的参数。
返回值:成功返回0;失败返回错误码。

一般用pthread_create函数创建新线程。下面是利用pthread_create函数创建新线程的代码:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
void *thread_run(void *arg)
{
    while(1)
    {
        printf("I am a thread!\n");
        sleep(1);
    }
}
int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_run, NULL);
    while(1)
    {
        printf("I am thread group!\n");
        sleep(1);
    }

    return 0;
}

代码中两个线程都每隔一秒向屏幕打印字符串,来看看执行效果:
这里写图片描述

也可以取得线程的线程ID:

#include <pthread.h>
pthread_t pthread_self(void);
返回值:调用线程的ID。

这里取得线程库pthread范围的线程ID,返回值为pthread_t类型数据, pthread_t 的具体类型取决于实现,Linux的NPTL实现中,pthread_t类型的线程ID,本质上是一个进程地址空间的地址。
也可以用:

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
pid_t tid;
tid = syscall(SYS_gettid);

这里取得内核级线程的线程ID,即pid。
可以将上面的代码稍微改一下:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run(void *arg)
{
    pthread_t tid = pthread_self();
    pid_t pid = syscall(SYS_gettid);
    while(1)
    {
        printf("I am a thread! user: %p, kernel: %d\n", tid, pid);
        sleep(1);
    }
}
int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_run, NULL);
    pthread_t ptid = pthread_self();
    pid_t pid = syscall(SYS_gettid);
    while(1)
    {
        printf("I am thread group! user: %p, kernel: %d\n", ptid, pid);
        sleep(1);
    }

    return 0;
}

运行代码可以得到这样的输出:
这里写图片描述

在多线程进程中,任何一个线程的异常终止都会导致整个进程的退出,如果仅要求线程退出而不终止整个进程可用下面三种方法:
1. 从线程函数return。这种⽅方法对主线程不适⽤用,从main函数return相当于调⽤用exit。
2. 线程可以调⽤用pthread_ exit终⽌止⾃自⼰己。
3. ⼀一个线程可以调⽤用pthread_ cancel终⽌止同⼀一进程中的另⼀一个线程。
pthread_exit函数:

void pthread_exit(void *value_ptr);
功能:进程终止。
参数
value_ptr:value_ptr不要指向⼀个局部变量。
返回值:⽆返回值,跟进程一样,线程结束的时候⽆无法返回到它的调用者(自身)。

注意,这里的返回值必须是全局的或用malloc分配的,不能是函数栈上的指针,因为当其他线程得到这个返回值时线程函数已经退出了。
pthread_cancel函数:

int pthread_cancel(pthread_t thread);
功能:取消一个执行中的线程。
参数
thread:线程ID。
返回值:成功返回0;失败返回错误码

要取得线程的返回值,就要用到进程等待函数pthread_join:

int pthread_join(pthread_t thread, void **value_ptr);
功能:等待线程结束,调用该函数的线程将挂起等待,直到id为thread的线程终⽌。
参数
thread:线程ID
value_ptr:它指向⼀个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码

新创建的线程默认为是joinable的,即可结合的,当线程退出后必须进程pthread_join操作。因为线程退出后其空间不能自动释放,必须显式回收,如果不进行释放的话新创建的线程不会复用刚刚的地址空间,这样就造成了内存泄漏。
线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
1. 如果thread线程通过return返回,value_ ptr所指向的单元⾥里存放的是thread线程函数的返回值。
2. 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_ CANCELED。
3. 如果thread线程是自己调用pthreadexit 终止的 ,valueptr所指向的单元存放的是传给pthread_exit的参数。
4. 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数。
代码:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run1(void *arg)
{
    printf("%s\n", (char*)arg);
    int *p = (int*)malloc(sizeof(int));
    *p = 1;
    sleep(2);
    return (void*)p;
}
void *thread_run2(void *arg)
{
    printf("%s\n", (char*)arg);
    int *p = (int*)malloc(sizeof(int));
    *p = 2;
    sleep(2);
    pthread_exit((void*)p);
}
void *thread_run3(void *arg)
{
    printf("%s\n", (char*)arg);
    while(1);
}
int main(void)
{
    pthread_t tid1, tid2, tid3;
    void *ret1, *ret2, *ret3;
    pthread_create(&tid1, NULL, thread_run1, "thread No1");
    pthread_create(&tid2, NULL, thread_run2, "thread No2");
    pthread_create(&tid3, NULL, thread_run3, "thread No3");
    //sleep(1);
    pthread_cancel(tid3);

    pthread_join(tid1, &ret1);
    printf("thread quit! thread id : %X, return code : %d\n", tid1, *(int*)ret1);
    free(ret1);
    pthread_join(tid2, &ret2);
    printf("thread quit! thread id : %X, return code : %d\n", tid2, *(int*)ret2);
    free(ret2);
    pthread_join(tid3, &ret3);
    if(ret3 == PTHREAD_CANCELED)
        printf("thread quit! thread id : %X, return code : PTHREAD_CANCELED\n", tid3);
    else
        printf("thread quit! thread id : %X, return code : NULL\n", tid3);


    return 0;
}

运行结果:
这里写图片描述

新创建的线程是可结合的,即需要调用pthread_join进行回收,而如果不需要线程函数的返回值,那么join就是一种负担,此时我们可以将线程声明为“分离”的,即当线程结束后系统自动释放线程资源。

#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:对线程thread进行分离。
返回值:成功返回0;错误返回错误编号。
线程也可以自己分离:
pthread_detach(pthread_self());

joinable与分离是冲突的,因此一个线程不能同时是joinable和分离的。
代码:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run(void *arg)
{
    pthread_detach(pthread_self());
    printf("%s\n", (char*)arg);
    return NULL;
}
int main(void)
{
    pthread_t tid;
    if(pthread_create(&tid, NULL, thread_run, "thread run") != 0)
    {
        printf("create thread errno\n");
        return 1;
    }
    printf("I am thread group!\n");
    sleep(1);
    if(pthread_join(tid, NULL) == 0)
        printf("thread wait success\n");
    else
        printf("thread wait failed\n");

    return 0;
}

先派生出一个线程,这个线程自己分离后执行后续操作,主线程调用pthread_join,如果等待成功则输出“thread wait success”,失败则输出“thread wait failed”,来看运行结果:
这里写图片描述
显然派生出的线程自动进行线程分离,主线程等待失败。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值