linux 线程

线程概念: 

LWP: light  weight process 轻量级进程,本质仍是进程(在 linux环境下)   

    进程:有独立的 进程地址空间。 有独立的pcb。   分配资源最小单位

    线程:有独立的 pcb。 没有独立的进程地址空间   执行最小单位

区别 :在于是否共享地址空间。  独居(进程) 合租(线程)

ps-Lf 进程id  --》线程号  LWP  -->CPU 执行的最小单位

在cpu眼里 线程 还是进程 一个进程中线程越多 获得cpu概率就越大   多到一定数量时概率又会下降

 

linux 内核线程实现原理

    类Unix 系统中,早期是没有线程概念的,80 年代才引入,借助进程机制实现了线程的概念。

    因此在这类系统中,进程和线程关系密切。

    1.轻量级进程(lwp) ,也有pcb,创建线程使用的底层函数和进程一样 都是 clone。

    2.从内核看进程和线程是一样的,都有各自不同的 pcb,但是pcb中指向内存资源的 三级页表是相同的

    3.进程可以蜕变成线程

    4.线程可以看做寄存器和栈的集合。

    5.在linux下,线程是最小的执行单位,进程是最小的分配资源单位


线程共享资源

    1.文件描述符

    2.每种信号的处理方式

    3.当前工作目录

    4.用户 ID 和组 ID

    5.内存地址空间 (.text/.data/.bss/heap/共享库) 

非共享资源:

    1.线程ID

    2.处理器现场(寄存器的值)和栈指针(内核栈 用来保存寄存器的值)

    3.独立的栈空间(用户空间栈)

    4。errno 变量

    5. 信号屏蔽字

    6.调度优先级

线程优缺点:


    优点:  1.提升程序并发性 2.开销小 3.数据通信  。共享数据方便

    缺点:  1.库函数不稳定   2 调试 、编写困难 、gdb不支持  3.对信号支持不好

    优点相对突出 、 确定均不是硬伤。 linux 下由于 实现方法导致进程线程 差别不是很大

//线程共享全局变量


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

int var = 100;

void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  var = 200;
  printf("thread ,var=%d\n",var);
  return NULL;
}
int main(){


  printf("At first var =%d\n",var);
  pthread_t tid;
  pthread_create(&tid,NULL,tfn,NULL);
  sleep(1);
  printf("after pthread_create,var=%d\n",var);
  return 0;
}

输出:

At first var =100
thread ,var=200
after pthread_create,var=200

 

线程控制原语:


    检查出错返回:  线程中

        fprintf(stderr,"xxxerror  %s\n",strerror(ret))

    pthread_t pthread_self(void); 获取线程ID 是在进程地址空间内部,用来标识线程身份的id号

        返回值:本线程id


    线程ID:在进程中 用来标识线程身份

    线程号 lwp:标识线程身份  给cpu看的
 

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

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

        参数1:传出参数,表新创建的子线程id

        参数2:线程属性。传NULL表示使用默认属性

        参数3:子线程回调函数。创建成功,pthread_create 函数返回时,该函数会被自动调用

        参数4:参数3 的参数 没有的话 传NULL

    返回值:成功 :0

        失败: errno

//创建一个线程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>



void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  printf("thread: pid =%d,tid= %lu\n",getpid(),pthread_self());
  return NULL;
}
int main(){


  pthread_t tid;

  tid = pthread_self();
  printf("%lu\n",tid);

  int ret = pthread_create(&tid,NULL,tfn,NULL);
  if(ret!=0){
    perror("pthread_create error");
  }
  printf("main: pid =%d,tid=%lu\n",getpid(),pthread_self());
  //sleep(1);
  // return 0;
  pthread_exit((void*)0);
}

输出:

139693159536448
main: pid =11447,tid=139693159536448
thread: pid =11447,tid= 139693151209216
 

 

循环创建 N个子线程:

    for(i=0;i<5;i++){


        pthread_create(&tid,NULL,tfd,(void*)i); //将int 类型 i ,强转成 void* ,传参


    void pthread_exit(void* retval); 退出当前线程

        retval: 退出值。 无退出值时 传 NULL

        exit() : 退出当前进程

        return :返回到调用者那里去

        pthread_exit(): 退出当前线程

//循环创建 5 个线程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>



void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  int i = (int)arg;//强转
  sleep(1);
  printf(":i'm %dth thread: pid =%d,tid= %lu\n",i+1,getpid(),pthread_self());
  return NULL;
}
int main(){


  int i;
  int ret;
  pthread_t tid;
  for(i=0;i<5;++i){
    ret = pthread_create(&tid,NULL,tfn,(void*)i);  //传参采用 值传递 借助强转
    if(ret!=0){
      sys_err("pthread_create error");
    }

  }
  printf("i'm main ,pid =%d,tid=%lu\n",getpid(),pthread_self());
  sleep(i);
  return 0;
}


输出:

i'm main ,pid =11998,tid=140291477743424
:i'm 3th thread: pid =11998,tid= 140291452630784
:i'm 4th thread: pid =11998,tid= 140291444238080
:i'm 1th thread: pid =11998,tid= 140291469416192
:i'm 2th thread: pid =11998,tid= 140291461023488
:i'm 5th thread: pid =11998,tid= 140291435845376
        
  

 int pthread_join(pthread_t thread,void** retval); 阻塞 回收线程


        thread: 待回收线程 ID

        retval: 传出参数, 回收的那个线程的退出值

            线程异常退出  值为 -1;

        返回值:成功: 0

            失败:errno

// pthread_join 函数 列子
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>


void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  return (void*)66;
}
int main(){

  pthread_t tid[5];
  int* retval;
  int i;
  for(i=0;i<5;++i){

    int ret = pthread_create(&tid[i],NULL,tfn,NULL);
    if(ret!=0){
      sys_err("pthread_create error");
    }
    ret = pthread_join(tid[i],(void**)&retval);
    if(ret!=0){
      sys_err("pthread_join error");
    }
    printf("child thread exit with  %d\n",retval);
  }


  pthread_exit(NULL);
}

输出:

 child thread exit with  66
child thread exit with  66
child thread exit with  66
child thread exit with  66
child thread exit with  66

  

// join 函数 列子 二
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>


struct thrd{
  int var;
  char str[256];
};
void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  struct thrd* tval;
  tval=(struct thrd*)malloc(sizeof(tval));
  tval->var=100;
  strcpy(tval->str,"hello thread");
  return (void*)tval;
}
int main(){


  pthread_t tid;
  struct thrd* retval;




  int ret = pthread_create(&tid,NULL,tfn,NULL);
  if(ret!=0){
    sys_err("pthread_create error");
  }
  ret = pthread_join(tid,(void**)&retval);
  if(ret!=0){
    sys_err("pthread_join error");
  }
  printf("child thread exit with var = %d,str =%s\n",retval->var,retval->str);

  pthread_exit(NULL);
}

输出:

child thread exit with var = 100,str =hello thread

 int pthread_detach(pthread_t thread);  设置线程分离  

 

设置线程分离,线程终止会自动清理pcb 无需回收


        thread:待分离的线程id

        返回值:成功: 0

            失败:errno

//设置线程 分离
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>



void sys_err(const char* str){
  perror(str);
  exit(1);
}
void* tfn(void* arg){
  (void)arg;
  printf("thread: pid =%d,tid= %lu\n",getpid(),pthread_self());
  return NULL;
}
int main(){


  pthread_t tid;


  int ret = pthread_create(&tid,NULL,tfn,NULL);
  if(ret!=0){
    fprintf(stderr,"pthread_create error:%s\n",strerror(ret));
    exit(1);
  }
  ret = pthread_detach(tid);//设置线程分离,线程终止会自动清理pcb 无需回收
  if(ret!=0){
    fprintf(stderr,"pthread_detach error:%s\n",strerror(ret));
    exit(1);
  }
  sleep(1);
  ret = pthread_join(tid,NULL);
  printf("join ret =%d\n",ret);
  if(ret!=0){
    fprintf(stderr,"pthread_join error:%s\n",strerror(ret));
    exit(1);
  }

  printf("main : pid=%d.tid=%lu\n",getpid(),pthread_self());
  pthread_exit((void*)0);
}


输出:

thread: pid =13036,tid= 140193968563968
join ret =22
pthread_join error:Invalid argument
   

 int pthread_cancel(pthread_t thread);  杀死一个线程 。 需要到取消点(保存点)


        thread : 待杀死线程id

        返回值: 成功: 0

            失败: errno

        如果,子线程没有到达取消点, 那么 pthread_cancel  无效

        我们可以在程序中,手动添加一个取消点 。使用pthread_testcancel()

        成功被 pthread_cancel()杀死的线程  返回 -1  使用pthread_join 回收

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

void* tfn(void* arg){
  (void)arg;
  while(1){

    printf("thread :pid =%d,tid=%lu\n",getpid(),pthread_self());


    sleep(1);
  }
  return NULL;
}
int main(){


  pthread_t tid;


  int ret = pthread_create(&tid,NULL,tfn,NULL);
  if(ret!=0){
    fprintf(stderr,"pthread_create errror :%s\n",strerror(ret));
    exit(1);
  }
  printf("main: pid =%d,tid=%lu\n",getpid(),pthread_self());
  sleep(3);
  ret = pthread_cancel(tid);//终止线程
  if(ret!=0){
    fprintf(stderr,"pthread_create errror :%s\n",strerror(ret));
    exit(1);

  }
  while(1);
  pthread_exit((void*)0);
}

 

输出:

main: pid =13230,tid=140582995310400
thread :pid =13230,tid=140582986983168
thread :pid =13230,tid=140582986983168
thread :pid =13230,tid=140582986983168
^C
 

// 杀死线程 3种 方法
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>

void* tfn1(void* arg){
  (void)arg;
  printf("thread 1 returning \n");
  return (void*)111;    
}
void* tfn2(void* arg){
  (void)arg;
  printf("thread 2 exiting\n");
  pthread_exit((void*)222);
}
void* tfn3(void* arg){
  (void)arg;
  while(1){
    //    printf("thread 3 :i'm going to die in 3 seconds---\n");
    //   sleep(1);
    //printf sleep 都有系统调用 都会进内核
    pthread_testcancel();//自己添加取消点
  }
  return (void*)666;
}
int main(){


  pthread_t tid;
  void* tret = NULL;



  pthread_create(&tid,NULL,tfn1,NULL);
  pthread_join(tid,&tret);
  printf("thread 1 eixt code = %d\n",tret);

  pthread_create(&tid,NULL,tfn2,NULL);
  pthread_join(tid,&tret);
  printf("thread 2 eixt code = %d\n",tret);

  pthread_create(&tid,NULL,tfn3,NULL);
  sleep(3);
  pthread_cancel(tid);
  pthread_join(tid,&tret);
  printf("thread 3 eixt code = %d\n",tret);

  pthread_exit((void*)0);
}

输出:

thread 1 returning 
thread 1 eixt code = 111
thread 2 exiting
thread 2 eixt code = 222
thread 3 eixt code = -1

   

线程控制原语                    进程控制原语

        

    pthread_create()                fork()

    pthread_self()                    getpid()

    pthread_eixt()                    exit()

    pthread_join()                    wait()/waitpid()

    pthread_cancel()                kill()

    pthread_detach()

线程属性:


    设置分离属性

    pthread_attr_t attr  创建一个线程属性结构体变量

    pthread_attr_init(&attr) 初始化线程属性

    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED)  设置线程属性为 分离太

    pthread_create(&tid,&attr,tfn,NULL)  借助修改后的 设置线程属性 创建为分离态的新线程

    pthread_attr_destroy(&attr)  销毁线程属性

//创建线程之前 设置分离属性

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
void* tfn(void* arg){
  (void)arg;
  printf("thread: pid =%d,tid= %lu\n",getpid(),pthread_self());
  return NULL;
}
int main(){


  pthread_t tid;
  pthread_attr_t attr;
  int ret = pthread_attr_init(&attr);
  if(ret!=0){
    fprintf(stderr,"attr_init error%s\n",strerror(ret));
    exit(1);
  }
  ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置线程属性为分离
  if(ret!=0){
    fprintf(stderr,"pthread_attr_setdetachstate error%s\n",strerror(ret));
    exit(1);
  }


  ret = pthread_create(&tid,&attr,tfn,NULL);
  if(ret!=0){
    fprintf(stderr,"pthread_creat error%s\n",strerror(ret));
    exit(1);
  }
  ret = pthread_attr_destroy(&attr);
  if(ret!=0){
    fprintf(stderr,"pthread_attr_destroy error%s\n",strerror(ret));
    exit(1);
  }
  sleep(1);
  ret = pthread_join(tid,NULL);
  if(ret!=0){
    fprintf(stderr,"pthread_join error:%s\n",strerror(ret));
    exit(1);
  }


  printf("main: pid =%d,tid=%lu\n",getpid(),pthread_self());
  pthread_exit((void*)0);
}

 

输出:

thread: pid =14146,tid= 140135779284736
pthread_join error:Invalid argument
 

 

线程使用注意事项:


    
        1.主线程退出其他线程不退出,主线程应调用pthread_ exit

        2.避免僵尸线程.

        pthread_ join。

        pthread_ detach.

        pthread_ .create 指定分离属性。

        被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程线中的值;

        3.malloc和mmap申请的内存可以被其他线程释放。

        4.应避免在多线程模型中调用fork除非,马上exec,子进程中只有调用fork的线程存在,其他线程在子进程

        中均pthread_ exit.

        5.信号的复杂语义 很难和多线程共存,应避免在多线程引入信号机制。


    


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux线程通信是指在Linux操作系统,不同线程之间进行信息交流和数据共享的机制。线程通信是多线程编程非常重要的一部分,它可以实现线程之间的协作和同步。 在Linux线程通信可以通过以下几种方式实现: 1. 共享内存:多个线程可以通过共享内存区域来进行数据的读写。线程可以访问同一块内存区域,从而实现数据的共享。需要注意的是,由于多个线程同时访问共享内存可能会导致数据竞争和不一致性问题,因此需要使用互斥锁或其他同步机制来保证数据的一致性。 2. 信号量:信号量是一种用于线程同步的机制,它可以用来控制对共享资源的访问。通过使用信号量,线程可以等待某个条件满足后再继续执行,或者通知其他线程某个条件已经满足。 3. 互斥锁:互斥锁是一种用于保护共享资源的机制,它可以确保在同一时间只有一个线程可以访问共享资源。当一个线程获得了互斥锁后,其他线程需要等待该线程释放锁才能继续执行。 4. 条件变量:条件变量是一种用于线程同步的机制,它可以让线程等待某个条件满足后再继续执行。条件变量通常与互斥锁一起使用,以确保在等待条件时不会发生竞争条件。 5. 管道:管道是一种用于进程间通信的机制,但在Linux也可以用于线程间通信。通过管道,一个线程可以将数据写入管道,另一个线程可以从管道读取数据。 6. 消息队列:消息队列是一种用于进程间通信的机制,但在Linux也可以用于线程间通信。通过消息队列,一个线程可以将消息发送到队列,另一个线程可以从队列接收消息。 7. 套接字:套接字是一种用于网络通信的机制,但在Linux也可以用于线程间通信。通过套接字,不同线程可以通过网络协议进行通信。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值