Linux---线程控制

目录

1、创建线程

2、线程终止

3、线程等待

4、线程分离


Linux下线程是使用进程模拟实现的,因此没有专门的系统调用来进行线程的各种操作(创建、终止等),Linux下线程控制都是通过POSIX线程库完成的。

1、创建线程

1)使用第三方库创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

         作用:在该函数被调用的进程中创建一个线程

         参数:thread:线程id,输出型参数   attr:暂时不需要关注,设为NULL即可   void *(*start_routine) (void *):参数和返回值均为void*函数指针,即该线程要执行的函数   arg:函数参数

         返回值:成功返回0,失败返回错误码

#include    
  #include    
  #include    
  void* fun(void *arg)    
  {    
    while(1)    
    {    
      printf("i am neww thread!process id : %d\n",getpid());    
      sleep(1);    
    }    
  }    
      
  int main()    
  {    
    pthread_t pt;    
    //创建线程    
    pthread_create(&pt,NULL,fun,NULL);    
      
    while(1)    
    {    
      printf("i am main thread!process id : %d -- %p\n",getpid(),pt);                                                                                                                      
      sleep(2);                                                                                                                                                         
    }                                                                                                                                                                   
    return 0;                                                                                                                                                           
  }                          

2)线程id和程序地址空间布局

调用pthread_create函数创建线程,会生以输出型参数的形式生成一个线程id,这个线程id用来唯一标识一个线程。通过上述代码输出结果,我们可以看到想爱你城id实际上是一个地址,pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID, 属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。线程库提供了pthread_self函数用于获取线程自身id.

pthread_t pthread_self();

Linux---线程控制_第1张图片

在Linux系统中,运行一个多线程程序,使用ps -aL命令可以看到以下信息:

Linux---线程控制_第2张图片

在一个包含两个线程的进程中,两个线程的pid都是相同的,但是除了pid还有一个LWP,表示什么呢?

在Linux中,线程是轻量级进程,LWP表示轻量级进程id,用来唯一标识一个轻量级进程。

Linux---线程控制_第3张图片

3)使用pthread_self查看线程id

pthread_t pthread_self(void);//查看该线程的线程id

4)总结

①什么是LWP

LWP是轻量级进程id。Linux中线程是用进程模拟实现的,创建一个线程在内核中会给该进程创建一个task_struct结构体,而task_struct是进程控制块,因此该进程称为轻量级进程。而LWP就是该轻量进程的id,用来唯一标识一个轻量级进程。

②pthread_create和LWP的关系

pthread_create是由第三方库提供的创建线程的函数,因此该函数不属于系统调用。使用该函数创建线程,需要由第三方库进行管理,而线程的管理也遵循“先描述在组织”的原则。创建线程会在用户区创建相应的数据结构,同时内核中也会为该线程创建task_struct结构体,用户区的数据结构需要通过LWP来找到该结构体实现线程相关的功能。

③轻量级进程id和进程id之间的区别

无论是进程id还是轻量级进程id它们的作用都是标识,在多线程程序中,所有线程的进程id是相同的,而轻量级进程id是不同的。操作系统中调度是以轻量级进程id进行调度的。

2、线程终止

进程的终止有三种方式,分别是:main函数中的return;任意位置调用exit;任意位置调用_exit。在线程中,线程的退出也有三种方式:

  • 线程中使用return。注意:主线程中调用return会导致进程退出
  • 在线程中调用pthread_exit()终止线程自身。
  • 在线程中调用pthread_cancel()终止其他进程。

1)pthread_exit()

void pthread_exit(void *retval);

        参数:输出型参数,返回线程的退出状态。当其他线程使用pthread_join等待该想爱你城时,可以通过pthread_join的第二个参数来获取该值。

注意:线程使用return和pthread_exit退出时,返回值必须是全局的或者是malloc分配的,因为当其他线程得到这个返回值时该线程已经退出。

2)pthread_cancel()

int pthread_cancel(pthread_t thread);

        参数:要终止的线程id

        返回值:成功返回0,失败返回错误码

3、线程等待

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

  • 当一个线程退出时,它的资源并没有被释放,仍然在进程的地址空间内。
  • 新创建的线程不会使用退出的线程的地址空间,因此就需要释放该线程资源。

2)pthread_join

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

      作用:等待指定id的线程结束,回收该线程的资源

      参数:thread:线程id   value_ptr:输出型参数

      返回值:成功返回0,失败返回错误码

注意

  • 如果thread线程是通过return返回,则value_ptr保存的是线程的退出码
  • 如果thread线程是通过调用thread_exit返回的,则value_ptr保存的thread_exit函数的参数
  • 如果thread线程是通过别的线程调用pthread_cancel退出的,则value_ptr保存的是一个宏PTHREAD_ CANCELED,该宏的值是-1
  • 如果不关注线程的退出状态,则可以将第二个参数给NULL。

3)三种方法退出一个线程并使用pthread_join等待该线程代码演示

 #include                                                                                                                                                                        
  #include    
  #include    
      
  /*    
  void* route1(void* arg)    
  {    
    printf("%s,id : %d\n",(char*)arg,pthread_self());    
    sleep(1);    
    //使用return退出    
    return (void*)0;    
  }    
  */    
      
  /*    
  void* a;    
  void* route1(void* arg)    
  {    
    printf("%s,id : %d\n",(char*)arg,pthread_self());    
    sleep(1);    
    //使用pthread_exit退出    
    a = (void*)10;    
    pthread_exit(a);    
  }    
  */    
      
  void* route1(void* arg)    
  {    
    printf("%s,id : %d\n",(char*)arg,pthread_self());    
    while(1);    
  }    
      
  int main()    
  {    
    //创建线程    
    pthread_t tid;    
    void* returnValue;    
    pthread_create(&tid,NULL,route1,"thread route1");    
    sleep(1);    
    pthread_cancel(tid);
    pthread_join(tid,&returnValue);
    printf("%dthread exit,exit code:%d\n",tid,(int*)returnValue);
    return 0;
  }           

4、线程分离

默认情况下,创建新线程是joinable的(可重入的),线程退出后需要使用pthread_join操作对该线程的资源进行回收,否则无法回收资源导致资源泄露。如果不关心退出线程的返回值,可以对该线程进行分离,分离的线程退出后会自动释放自己得资源。

int  pthread_detach(pthread_t thread);

      参数:要分离的线程id

      返回值:成功返回0,失败返回退出码(返回值)

注意:线程分离可以是被别的线程分离,也可以是自己对自己进行分离。一个线程要么是joinable,要么是分离的,不可能即是joinble又是分离的(分离和joinable是冲突的)

#include    
#include    
#include    
      
void* fun(void* arg)    
{    
    //线程自身分离    
    pthread_detach(pthread_self());    
    //打印分离成功    
    printf("detach success,thread id : %d\n",pthread_self());    
    sleep(3);    
    return NULL;//不关心返回结果,返回空    
}    
      
int main()    
{    
    //创建一个新线程    
    pthread_t tid;    
    if(pthread_create(&tid,NULL,fun,NULL) == 0)    
      printf("create success!\n");    
    sleep(1);//等待新线程分离    
    if(pthread_join(tid,NULL) == 0)                                                                                                                                                        
      printf("wait success!\n");    
    else    
      printf("wait fail!quit!!!\n");    
    return 0;    
}    

你可能感兴趣的:(Linux,linux,操作系统,多线程)