Linux多线程笔记

进程创建完线程之后,地址空间没有变化,进程退化成了线程——主线程。

创建出的子线程和主线程共用地址空间,但主线程和子线程有各自独立的pcb,

子线程的pcb是从主线程拷贝来的。

  • 在Linux下:
    • 内核只看pcb,所以在Linux看起来,线程就是进程,轻量级的进程。
  • 多线程和多进程的区别:
    • 多进程:
      • 始终共享的资源:
        • 代码
        • 内存映射区
        • 文件描述符
    • 多线程共享资源
      • 全局变量

线程更节省资源,内核只认pcb,看到这么多pcb就分配这么多时间片过来,效率不变,但线程资源占用的更少了。

主线程和子线程

  • 共享:
    • .text
    • .bss
    • .data
    • 动态库加载区
    • 环境变量
    • 命令行参数
    • 通信:全局变量,堆
  • 不共享:
    • 栈区
    • 如果有5个线程,栈区被平均分成5分

创建线程

  • 函数原型:

    • 1
      2
      3
      4
      5
      6
      7
      8
      //如果成功0,失败返回错误号
      //不能使用perror()了,因为没有生成errornumber
      int pthread_create(
      pyhread_t* thread,//线程ID(无符号长整数),是传出参数
      const pthread_attr_t *attr,//线程属性,NULL
      void*(*start_routine)(void*),//线程处理函数
      void *arg //线程处理函数参数
      )
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      #include<pthead.h>//线程对应的头文件
      void* myfunc(void* arg)
      {
      // 打印子线程的id
      printf("child thread id: %lu\n",pthread_self());
      return NULL;
      }
      int main(int argc,const char* argv[])
      {
      //创建一个子线程
      //线程ID
      pthread_t pthid;
      pthread_create(&pthid,NULL,myfunc,NULL);
      printf("parent thread id:%lu\n",pthread_self());
      sleep(2);
      return 0;
      }

编译时要连接库:-lpthread

线程思维

例如如下代码,运行时不会按照预期:

运行时,线程打印的i-th有重复的,

原因是因为线程抢占cpu时是分片的:

几个线程获得的都是主线程的i的内存地址,而这个i一直都是变化的。

打印返回错误信息

1
char *strerror(int errnum);

单个协程退出

函数:void pthread_exit(void *retval);

  • retval 指针会带一些信息,必须指向全局或堆的。退出不携带信息则用NULL

阻塞等待线程退出

并获取线程退出状态

函数:int pthread_join(pthread_t thread,void **retval);

  • thread:要回收的子线程的线程id
  • retval:读取线程退出的时候携带的状态信息
    • 传出参数
    • void *ptr;
    • pthread_join(pthid,&ptr);
    • 指向的内存和pthread_exit参数指向同一块内存地址

线程分离

一般线程分离是在线程创建时pthread_create的线程属性设置分离。

也可以使用pthread_detach进行设置线程分离,但不常用。

函数:intpthread_detach(pthread_t thread);

  • 调用该函数之后不需要pthread_join
  • 子线程会自动回收自己的pcb

使用设置属性设置线程分离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<pthead.h>//线程对应的头文件
void* myfunc(void* arg)
{
// 打印子线程的id
printf("child thread id: %lu\n",pthread_self());
return NULL;
}
int main(int argc,const char* argv[])
{
//创建一个子线程
//线程ID
pthread_t pthid;
//初始化线程的属性
pthread_attr_t attr;
pthtread_attr_init(&attr);
// 设置分离
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//创建线程的时候设置线程分离
pthread_create(&pthid,&attr,myfunc,NULL);
printf("parent thread id:%lu\n",pthread_self());
sleep(2);
//释放资源
pthread_attr_destroy(&attr);
return 0;
}

杀死(取消)线程

函数:pthread_cancel(ptread_t thread);

  • 注意事项:
    • 在要杀死的子进程对应处理的函数内部,必须做一次系统调用。
    • 没有调用系统调用的地方可以使用pthread_testcancel设置一个取消点

多线程数据混乱

原因:

  • 多线程操作了共享的资源
  • 因为cpu调度问题

解决:

  • 线程同步
  • 什么叫同步
    • 协同步调,按照先后顺序执行操作
    • 本来多线程访问共享资源的时候,可以并行,通过加锁机制,并行——>串行。

本文标题:Linux多线程笔记

文章作者:Yang Shuai

发布时间:2019年03月12日 - 17:03

最后更新:2019年03月12日 - 17:03

原始链接:https://ysbbswork.github.io/2019/03/12/Linux多线程笔记/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!