线程控制+线程tid+线程局部存储+线程私有栈

线程控制函数

今天学习的都是linux线程库中的函数。

pthread_creat()创建线程

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

参数

  1. thread:返回线程ID
  2. attr:设置线程的属性,attr为NULL表示使用默认属性(默认nullptr
  3. start_routine:是个函数地址,线程启动后要执行的函数
  4. arg:传给线程启动函数的参数

返回值

  • 成功返回0;失败返回错误码

pthread_exit()线程终止

void pthread_exit(void *value_ptr);

参数:

  • value_ptr:value_ptr不要指向一个局部变量。最好指向堆上空间

返回值:

  • 没有返回值谢谢。

这个函数类似于线程函数返回,可以说是等同于return。子进程退出正常退出不影响其他线程

线程控制+线程tid+线程局部存储+线程私有栈_第1张图片

但是主线程调用该函数的时候,与return有极大的区别。

线程控制+线程tid+线程局部存储+线程私有栈_第2张图片

 主线程return退出线程控制+线程tid+线程局部存储+线程私有栈_第3张图片

 主线程pthread_exit退出

线程控制+线程tid+线程局部存储+线程私有栈_第4张图片

pthread_cancel()线程终止

int pthread_cancel(pthread_t thread)

参数:

  • thread:线程ID

返回值:

  • 成功返回0;失败返回错误码,成功也没必要返回。

和pthread_exit一样,子终止,主进程不影响,主进程终止,子进程不影响。

配合函数pthread_self()

pthread_t pthread_self(void);

无需传参,哪个线程调用就返回该线程id。

配合使用:pthread_cancel(pthread_self());//中止当前进程。

pthread_join()线程等待

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

参数:

  1. thread:线程ID value_ptr:
  2. 它指向一个指针,后者指向线程的返回值

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

就是线程结束的时候返回值可以用join的第二个参数保持。

void*function(void*ags)
{
  int cnt=0;
  int*data=new int[5];
  while(1)
  {
    sleep(1);
    data[cnt]=cnt;
    cout<<"new thread cnt:"<

线程控制+线程tid+线程局部存储+线程私有栈_第5张图片

 主进程以阻塞的方式等待编号为tid的线程退出。可以以非阻塞的方式等待退出吗?不可以。

无视线程,对线程分离。

int pthread_detach();线程分离

int pthread_detach(pthread_t thread);

参数:

  • 想要分离的线程id

返回值:

  • 成功0,失败错误码

可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:

pthread_detach(pthread_self());

joinable和分离是冲突的,一个线程不能既是joinable又是分离的。

void*function(void*ags)
{
  pthread_detach(pthread_self());
  sleep(1);
  return nullptr;
}

int main()
{
  pthread_t tid;
  pthread_t maintid=pthread_self();
  pthread_create(&tid,nullptr,function,(void*)maintid);
  sleep(2);
  int n=pthread_join(tid,nullptr);
  cout<<"n:"<

分离的线程不可以被主线程等待,但是分离的线程也是整个进程的线程,一旦异常也会对整个进程造成影响。

pthread_kill()对线程发送信号

int pthread_kill(pthread_t thread, int sig);

参数:

  1. thread:接收信号的线程id
  2. 发送的信号

返回值:

  • 成功返回1,失败返回错误码。

与kill系统函数不同,如果用kill发送信号给同进程的其他线程,那么也只会自己接收到,而pthread_kill则是精准的发送给对应的线程。

对线程id理解

int main()
{
  pthread_t tid=pthread_self();
  printf("tid:%d  16进制tid:%p \n",tid,tid);
    //。。。。。。
}

看起来我们的tid好像一个地址信息。

其实tid就是地址信息,对应的线程其实是操作系统在进程的共享区开辟的一块空间,一份线程一份空间,我们的tid线程id其实是线程空间的起始地址。

线程控制+线程tid+线程局部存储+线程私有栈_第6张图片

对线程栈与局部存储理解

不同的线程在运行期间调用着不同的函数在系统中运行,但是栈区只有一个,每个线程的函数栈帧也不同,一个栈区无法满足多个线程同时运行,所以OS就在地址空间的共享区中,开辟了子线程的自己的栈区,而原先的栈区在多线程与单线程下都是给主线程来运行的。

线程控制+线程tid+线程局部存储+线程私有栈_第7张图片

 局部存储

线程也有着自己的局部存储空间,保存这一些私有的数据。

我们定义一个全局变量,然后子线程与主线程同时打印数据与地址,然后子线程修改全局变量,然后继续打印。

int g_val=0;
void*childfunction(void*ags)
{
  int cnt=0;
  while(1)
  {
    printf("child thread g_val:%d  &g_val:%p  cnt:%d\n",g_val,&g_val,++cnt);
    if(cnt==5)
    {
      printf("child change data\n");
      g_val=1;
    }
    sleep(1);
  }
  return nullptr;
}

int main()
{
  pthread_t tid;
  pthread_create(&tid,nullptr,childfunction,nullptr);
  while(1)
  {
    printf("main thread g_val:%d  &g_val:%p\n",g_val,&g_val);
    sleep(1);
  }
   //........
}

线程控制+线程tid+线程局部存储+线程私有栈_第8张图片

父子线程共享该全局变量,如果不想共享数据,可以在全局变量前加修饰符__thread。这个时候在编译的时候就会在子线程共享区中生成私有的全局变量。

__thread int g_val=0;

线程控制+线程tid+线程局部存储+线程私有栈_第9张图片确实全局数据被不同的进程访问的是不一样的了。

但是观察发现,似乎主线程的全局数据地址也在共享区,的确主线程也有着自己的线程结构体。

线程控制+线程tid+线程局部存储+线程私有栈_第10张图片 主线程也有对应的,线程数据结构。

 

你可能感兴趣的:(开发语言,linux)