线程

线程的思维导图:

一,什么是线程

1,线程的概念

线程是“一个进程内部的控制序列”。在linux下,PCB就是线程,是一个轻量级的进程。

2,进程和线程的区别

  • 进程是操作系统分配资源的一个基本单位
  • 线程是操作系统CPU调度的一个基本单位
  • 进程是一个或多个执行流的线程组,即一个进程可拥有多个线程

3 .线程的共享与独享

由于同一进程的多个线程共享同一地址空间,所以代码段,数据段是共享的,如果定义一个函数(存储在代码段),各线程都可以进行调用,如果定义个全局变量(存储在数据段),在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境: 
(1).文件描述符表 
(2).每种信号的处理方式(SIG_IGN,SIG_DFL,用户自定义) 
(3).当前工作目录 
(4).用户id和组id 
但有些资源是线程独享的: 
(1).线程id 
(2).上下文,包括各种寄存器的值,程序计数器和栈指针 
(3).栈空间 ,防止调用栈混乱
(4).errno变量 
(5).信号屏蔽字 
(6).调度优先级 

4,线程的优缺点

   优点:

  • 创建一个新线程的代价要比创一个新进程小得多
  • 线程之间的切换需要操作系统做的工作要少很多
  • 占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 线程可以同时等待不同的I/O操作

   缺点:

  • 性能损失:增加了额外的同步和调度开销,而可用的资源不变
  • 健壮性降低:因时间分配上的细微偏差 或者因共享了不该共享的变量造成不良影响的可能性是很大的
  • 编程难度提高:编写与调试一个多线程程序比单线程程序困难得多
  • 缺乏访问控制:在线程中调用exit()函数,将退出进程

二,线程控制

1.线程的创建


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:传给线程启动函数的参数

创建线程代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
void *thr_start(void *arg)
{
    while(1) {
        printf("thread:calling!!\n");
        sleep(1);
    }
    return NULL;
}
int main()
{
    pthread_t tid;
    //pthread_create 创建线程,线程入口函数为thr_start
    int ret = pthread_create(&tid, NULL, thr_start, NULL);
    if (ret != 0) {
        printf("pthread_create error!!\n");
        return -1;
    }
    while(1) {
        printf("thread:playing!!\n");
        sleep(1);
    }
    return 0;

创建成功就会出现:playing和calling循环打印,按快捷键Ctrl+c终止

2,线程终止

调用exit()的话,主进程会终止。终止线程由三种方法: 

pthread_exit函数

void pthread_exit( *value_ptr);
//功能
结束当前线程(结束自己),线程私有资源被释放
//参数
ptr不能是局部变量
ptr可被其他线程通过pthread_join获取
  • pthread_cancel函数 
//功能:取消一个执行中的线程(终止同一进程中的另一个线程)
//原型
 int pthread_cancel(pthread_t thread);
//参数
 thread:线程ID
//返回值:成功返回0;失败返回错误码
  • 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。

测试代码:

void *thr_start(void *arg)
{
    pthread_t mid = (pthread_t)arg;
    pthread_cancel(mid);//终止主线程
    while(1) {
        printf("i am child thread!!\n");
        sleep(1);
        //return NULL;//终止普通线程
        //printf("--------exit!!\n");
    }
    printf("--------exit!!\n");
    return NULL;
}
int main()
{
    pthread_t tid;

    pthread_t mid = pthread_self();

    int ret = pthread_create(&tid, NULL, thr_start, (void*)mid);
    if (ret != 0) {
        printf("pthread_create error\n");
        return -1;
    }
    //pthread_cancel(tid);//终止普通线程
    while(1) {
        printf("this is main thread!\n");
        sleep(1);
        //pthread_exit(NULL);//终止主线程
    }
    return 0;
}

3.线程等待与分离

  • 线程等待:线程的等待是以阻塞式等待,线程不等待会产生内存泄露(类似进程的僵尸进程) ​​​​​​​
//功能:等待线程结束
原型
 int pthread_join(pthread_t thread, void **value_ptr);
参数
 thread:线程ID
 value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码

已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。 创建新的线程不会复用刚才退出线程的地址空间,所以需要线程等待。调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得 到的终止状态是不同的。

  • 线程分离:当线程退出时,自动释放线程资源。
int pthread_detach(pthread_t thread); 

//可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离: 
pthread_detach(pthread_self()); 

线程有两种状态,一种为可结合的,一种为分离的,一般默认下线程是可结合的。

一个线程没有退出,主线程便一直等待其运行结束,对其资源进行回收,这种状态就称为可结合的。

但是一个线程要是被设置为分离的,那么主线程便不会在去等待回收那个线程,这个线程运行结束时会由操作系统对其进行资源回收,而且一个分离线程是不能被其他线程所结束掉的

注意:当一个进程结束时,其有一个分离的线程还未结束,那么其将会被强制结束,因为线程的资源都是进程分配给它的,而进程结束时其资源会被操作系统回收,此时线程会被结束掉。 当一个线程被设置为分离时,就不能被等待。joinable和分离是冲突的,一个线程不能既是joinable既是分离的。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值