线程控制

线程控制

POSIX线程库

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
  • 要使用这些库函数,要引入头文件 pthread.h
  • 链接这些线程函数库时要使用编译器命令“-lpthread” 选项

创建线程:

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;失败返回错误码

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

void *rout(void *arg){
    (void)arg;
    while(1){
        printf("I am thread 1\n");
        sleep(1);
    }
}

int main(void){
    pthread_t tid;
    int ret;
    if((ret = pthread_create(&tid, NULL, rout, NULL)) != 0){
        fprintf(stderr, "pthread_create:%s\n", strerror(ret));
        exit(EXIT_FAILURE);
    }

    while(1){
        printf("I am main thread\n");
        sleep(1);
    }
}

进程ID和线程ID

  • 在Linux中,目前线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被称为轻量级进程,每一个用户态的线程,在内核中对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)。
  • 没有线程之前,一个进程对应内核里一个进程描述符,对应一个进程ID。但是引入线程概念之后,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核态都有自己的进程描述符,进程和内核的描述符一下变成1 : N的关系,POSIX标准又要求进程内所有线程调用getpid函数时返回相同的进程ID,如何解决上述问题呢?
  • Linux引入了线程组的概念。
struct task_struct {
    ...
    pid_t pid;
    pid_t tgid;
    ...
    struct task_struct* group_leader;
    ...
    struct list_head thread_group;
    ...
  • 多线程的进程,又被称为线程组,线程组内的的每一个线程在内核中都有一个进程描述符与之对应。进程描述符中的pid对应线程id;进程描述符中的tgid,含义是Thread Group ID,该值对应的是用户层面的进程ID。

这里写图片描述

线程ID及进程地址空间布局

  • pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面所说的线程ID不一样。
  • 前面的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一标识一个线程。
  • pthread_create函数产生并标记在第一个参数指向的地址中的线程ID中,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
  • NPTL提供了pthread_self函数获得自身ID。
pthread_t pthread_self(void)

这里写图片描述

线程终止

如果要终止某一个进程而不终止整个进程,可以有三种方法:

  1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit.
  2. 线程可以调用pthread_exit终止自己
  3. 一个线程可以调用pthread_cancle终止同一个进程中的另外一个线程。

Pthread_exit函数

功能:线程终止
原型: void pthread_exit(void* value_ptr)
参数: value_ptr:value_ptr不要指向一个局部变量
返回值: 无返回值

pthread_cancel函数

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

线程等待与分离

线程等待
为什么线程需要等待?

  • 已经退出的线程,其空间没有被释放,仍然在进程地址空间内。
  • 创建新的线程不会复用刚才退出线程的地址空间。
功能:等待线程结束
原型:
    int pthread_join(pthread_t thread, void **value_ptr)
参数:
    thread:线程ID
    value_ptr:它指向一个指针,该指针指向线程的返回值。
返回值:成功返回0;失败返回错误码。

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread通过不同方法终止,通过phread_join得到的终止码是不同的。

1.如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2.如果thread线程被别的函数调用phread_cancle异常终止掉,value_ptr所指向的单元里存放的是常数PThREAD_CANCLEED
3.如果thread线程是自己调用pthread_exit ()终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
4.如果对thread线程的终止状态不感兴趣可以穿参数NULL

发布了66 篇原创文章 · 获赞 22 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章