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

线程控制函数

今天学习的都是linux线程库中的函数。<pthread.h>

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。子进程退出正常退出不影响其他线程

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

 主线程return退出

 主线程pthread_exit退出

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:"<<cnt++<<endl;
    if(cnt==5)
    {
      break;
    }
  }
  return (void*)data;
}


int main()
{
  pthread_t tid;
  pthread_create(&tid,nullptr,function,nullptr);
  int*data=nullptr;
  pthread_join(tid,(void**)&data);
  for(int i=0;i<5;i++)
  { 
    cout<<data[i]<<' ';
  }
    //。。。。。。。。。
}

 主进程以阻塞的方式等待编号为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:"<<n<<" 错误信息"<<strerror(n)<<endl;
} 

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

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其实是线程空间的起始地址。

对线程栈与局部存储理解

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

 局部存储

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

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

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);
  }
   //........
}

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

__thread int g_val=0;

确实全局数据被不同的进程访问的是不一样的了。

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

 主线程也有对应的,线程数据结构。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云的小站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值