线程

有的时候,我们需要在一个基础中同时运行多个控制流程。例如:一个图形界面的下载软件,在处理下载任务的同时,还必须响应界面的对任务的停止,删除等控制操作。这个时候就需要用到线程来实现并发操作。

和信号处理函数的控制在处理完信号之后就结束不同的是,多线程的控制流程可以长期并存,操作系统会在各线程之间调度和切换,就像在多个进程之间调度和切换一样,但创建线程开销要比进程小得多。因此,线程往往也被称作轻量级的进程。

由于同一进程的多个线程共享同一地址空间,数据段是共享的,如果定义一个全局变量,在各线程中都可以访问到。但有,些资源依然是每个线程各有一份的:

  • 线程id
  • 上下文,包括各种寄存器的值、程序计数器和栈指针
  • 栈空间
  • errno变量
  • 信号屏蔽字
  • 调度优先级

我们一般用到的是由POSIX标准定义的线程库函数,称为POSIX thread或者pthread。在Linux上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项。

创建线程

在POSIX库中,创建线程是通过函数实现的,它的声明如下:

  1. #include <pthread.h>
  2. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

它有四个参数,

  • 第一个参数thread为创建后的线程标识符的指针。
  • 第二个参数attr为线程属性,可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程),一般是直接用NULL。
  • 第三个参数start_routine为线程的运行函数
  • 第四个参数arg为线程运行函数的参数

创建成功时,返回0,失败是返回错误码。这个和其它的系统函数失败返回-1,由errno返回错误码不大一样。

等待线程结束

有的时候,我们需要等待线程结束,此时才能继续执行后面的事情。拿前面的例子来说,如果不等待线程结束,则主线程(main函数)会直接往下执行导致程序退出,线程函数都无法得到执行。

pthread库中等待线程结束的函数是pthread_join,它的声明如下:

  1. #include <pthread.h>
  2. int pthread_join(pthread_t thread, void **retval);

它有两个参数,

  • 第一个参数是线程标识符,
  • 第二个参数是个出参,用户获取线程函数的返回值。

终止线程

终止线程的方法一般来说有如下几种:

  • 线程函数调用return终止自己
  • 线程调用pthread_exit终止自己
  • 线程可以调用pthread_cancel终止同一进程中的其它线程

其中,方法1和方法2都是通过结束线程函数来实现主动退出的,它们是比较常用的方法。方法3则是一种强制终止的做法,这个方法一个问题就是导致对象的析构函数可能无法执行,会出现资源泄漏,并不推荐用这种方法。

一个简单的示例

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <pthread.h>
  5. #include <unistd.h>
  6. void* thr_fn(void *arg)
  7. {
  8. pid_t pid = getpid();
  9. pthread_t tid = pthread_self();
  10. printf("%s pid %u tid %u (0x%x)\n", arg, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
  11. return NULL;
  12. }
  13. int main(void)
  14. {
  15. pthread_t ntid = {0};
  16. int err = pthread_create(&ntid, NULL, thr_fn, (void*)"new thread: ");
  17. if (err != 0)
  18. {
  19. fprintf(stderr, "can't create thread: %s\n", strerror(err));
  20. exit(1);
  21. }
  22. void *tret;
  23. pthread_join(ntid, &tret);
  24. printf("thread exited\n");
  25. return 0;
  26. }

编译程序

  1. gcc thread.c -o thread -lpthread

运行结果

  1. new thread: pid 21231 tid 1082132800 (0x40800940)
  2. thread exited

Linux高级编程--08.线程概述的更多相关文章

  1. Linux高级编程--09.线程互斥与同步

    多个线程同时访问共享数据时可能会冲突,比如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成: 从内存读变量值到寄存器 寄存器的值加1 将寄存器的值写回内存 假设两个线程在多处理器平台 ...

  2. Linux高级编程--06.进程概述

    进程控制块 在Linux中,每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,它通常包含如下信息: 进程id.系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非 ...

  3. linux高级编程基础系列:线程间通信

    linux高级编程基础系列:线程间通信 转载:原文地址http://blog.163.com/jimking_2010/blog/static/1716015352013102510748824/ 线 ...

  4. 【UNIX环境高级编程】线程同步

    当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图.如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题.同样,如果变量是只读的也不会有一致性问题.但是,当一个线程可 ...

  5. Linux高级编程--04.GDB调试程序(入门概述)

    GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试 ...

  6. linux高级编程

    系统调用 01.什么是系统调用? 02.Linux系统调用之I/O操作(文件操作) 03.文件描述符的复制:dup(), dup2() 多进程实现多任务 04.进程的介绍 05.Linux可执行文件结 ...

  7. linux高级编程补充知识

    F: 计算机系统结构: ------------------------------- 应用程序 ----------------- |  库函数 -------------------------- ...

  8. Linux高级编程--10.Socket编程

    Linux下的Socket编程大体上包括Tcp Socket.Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较 ...

  9. Linux高级编程--05.文件读写

    缓冲I/O和非缓冲I/O 文件读写主要牵涉到了如下五个操作:打开.关闭.读.写.定位.在Linux系统中,提供了两套API, 一套是C标准API:fopen.fclose.fread.fwrite.f ...

随机推荐

  1. XML的简单学习

    推荐入门级学习XML网址W3c     http://www.w3school.com.cn/xml/xml_intro.asp 1: XML 指可扩展标记语言    XML 被设计用来传输和存储数据 ...

  2. ES6类与模块

    class Animal { // 构造方法,实例化的时候会被调用,如果不指定,那么会有一个不带参数的默认构造函数 constructor(name, color) { this.name = nam ...

  3. 详解Bootstrap列表组组件

    列表组可以用来制作列表清单.垂直导航等效果,也可以配合其他的组件制作出更漂亮的组件,列表组在bootstrap框架中也是一个独立的组件,所以也对应有自己独立源码: LESS:list-group.le ...

  4. Couldn't create temporary file to work with

    Ubuntu中当你编译安装软件的时候可能会出现Couldn't create temporary file to work with,原因可能是: 1.权限问题  2.根目录下没有tmp文件夹 解决办 ...

  5. 从零开始编写自己的C#框架 ---- 系列文章

    目录: 从零开始编写自己的C#框架(1)——前言从零开始编写自己的C#框架(2)——开发前的准备工作从零开始编写自己的C#框架(3)——开发规范从零开始编写自己的C#框架(4)——文档编写说明从零开始 ...

  6. 充分利用 UE4 中的噪声

    转自:https://www.unrealengine.com/zh-CN/blog/getting-the-most-out-of-noise-in-ue4 UE4 推出基于材质的程序式噪声已经有一 ...

  7. 搞了台2ussd服务器

    只上了一颗CPU,内存还没有双通道

  8. SSD在SQLServer中的应用

        一. 首先,回顾一下 SSD 的读写特性 (1)有限次数写:        (2)随机读性能最好:        (3)顺序读性能好:        (4)顺序写性能差:        (5) ...

  9. http 请求类

    1.httpclient请求类 代理demo:http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/examples/org/apac ...

  10. 用Storm轻松实时大数据分析【翻译】

    原文地址 简单易用,Storm让大数据分析变得轻而易举. 如今,公司在日常运作中经常会产生TB(terabytes)级的数据.数据来源包括从网络传感器捕获的,到Web,社交媒体,交易型业务数据,以及其 ...