线程控制

一、创建线程

#include <pthread.h>

int pthread_create(pthread_t *restrict thread,

const pthread_attr_t *restrict attr,

void *(*start_routine)(void *), void *restrict arg);

注:

1.restrict关键字作用是当访问这片内存空间时,只能用这个指针来操作,防止用其他间接的方法改变里面的值,保证了安全性

2.thread参数结果参数,是pthread_create函数传出来的参数(注意并不是传入参数)

3.void *(*start_routine)(void *) 是一个函数指针,返回值void *,参数void *

4.arg参数是start_routine函数的参数,像pthread_create这样,它的参数里有另一个函数及这个函数的参数,叫作回调函数。这是函数设计者为了方便后人,交由后人实现具体功能。

5.返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其他函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。

二、获得当前线程id

#include <pthread.h>

pthread_t pthread_self(void);

Compile and link with -lpthread.

返回值:总是成功返回,返回调用该函数线程ID

代码演示:

#include "./common/head.h"

/*功能:
 *创建一个子线程,打印主线程和子线程的pid和tid。
*/

//打印pid、tid
void printid(const char *tip)
{    
    pid_t pid = getpid();
    pthread_t tid = pthead_self();

    printf("%s pid:%d tid:%d(%p)", tip, pid, tid, tid);
    return ;
}

//子线程运行函数
void *thread_fn(void *str)
{
    printid(str);    //打印子线程的pid和tid
    
    return NULL;
}

int main()
{
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, thread_fn, "new  thread");
    if(ret){    //pthread_create若失败则返回errno
        printf("pthread_create:%s\n", strerror(ret));    //strerror函数将errno转成对应的字符串
        exit(1);
    }

    sleep(1);    //等待子线程先打印,否则一旦主线程运行结束,子线程还没来得及运行
    printid("main thread");    //打印主线程的pid和tid

    return 0;
}

结果:

        主线程和子线程拥有相同的进程id,而线程id却不同。 

拓展:

        主线程在全局变量ntid中保存了新创建的线程id,如果新创建的线程不调用pthread_self而是直接打印这个ntid,会得到上面相同的结论。

如果需要终止某个线程而不终止整个进程,可以有3种方法

1.从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。

2.一个线程可以调用pthread_cancel终止同一进程中的另一个线程。

3.线程可以调用pthread_exit终止自己。

#include <pthread.h>

void pthread_exit(void *value_ptr);

value_ptr是void *类型,和线程函数返回值的用法一样,其他线程可以调用pthread_join获得这个指针。

需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其他线程得到这个返回指针时线程函数已经退出了

#include <pthread.h>

int pthread_join(pthread_t thread, void **value_ptr);

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

1.如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。

2.如果thread线程被别的线程调用pthread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。

3.如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。

4.如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数。

代码演示:

#include "./common/head.h"

/*功能:
 *创建3个线程,线程死亡原因分别为:return、调用pthread_exit、被其他线程用pthread_cancel终止。
 *主线程用pthread_join获得各个线程的死亡信息,并打印出来。
*/

//线程1,return
void *thr_fn1(void *arg)
{
    printf("thread 1 return\n");
    return (void *)1;
}

//线程2,调用pthread_exit
void *thr_fn2(void *arg)
{
    printf("thread 2 exit\n");
    pthread_exit((void *)2);
    return NULL;
}

//线程3,一直睡觉,等待主线程pthread_cancel终止
void *thr_fn3(void *arg)
{
    while(1){
        printf("thread 3 sleep\n");
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    void *sts;

    //线程1运行,主线程等待给它收尸,并打印退出信息
    pthread_create(&tid, NULL, thr_fn1, NULL);
    pthread_join(tid, &sts);
    printf("thread 1 exit with code %ld\n", (long)sts);

    //线程2运行,主线程等待给它收尸,并打印退出信息
    pthread_create(&tid, NULL, thr_fn2, NULL);
    pthread_join(tid, &sts);
    printf("thread 2 exit with code %ld\n", (long)sts);

    //线程3运行,主线程pthread_cancel终止该线程,并打印退出信息
    pthread_create(&tid, NULL, thr_fn3, NULL);
    sleep(3);
    pthread_cancel(tid);
    pthread_join(tid, &sts);
    printf("thread 2 exit code %ld\n", (long)sts);    //PTHREAD_CANCELED

    return 0;
}

结果: 

拓展:

如果一个线程被设置成detach状态,则当线程结束后,会自动释放空间,不必等其他线程来给收尸(与进程处理动作设置为SIG_IGN相似)。另外,如果一个线程被多个线程收尸,结果是无法预测的 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值