一、Linux环境下的线程

  相对于其他操作系统,Linux系统内核只提供了轻量级进程的支持,并未实现线程模型。Linux是一种“多进程单线程”的操作系统,Linux本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。

进程是资源分配的单位,同一进程中的多个线程共享该进程的资源(如作为共享内存的全局变量)。Linux中所谓的“线程”只是在被创建时clone了父进程的资源,因此clone出来的进程表现为“线程”,这一点一定要弄清楚。因此,Linux“线程”这个概念只有在打引号的情况下才是最准确的。

  目前Linux中最流行的线程机制为LinuxThreads,所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。LinuxThreads由Xavier Leroy负责开发完成,并已绑定在GLIBC中发行,它实现了一种BiCapitalized面向Linux的Posix 1003.1c “pthread”标准接口。Linuxthread可以支持Intel、Alpha、MIPS等平台上的多处理器系统。

  需要注意的是,Linuxthread线程模型存在一些缺陷,尤其是在信号处理、调度和进程间同步原语方面都存在问题。并且,这个线程模型也不符合POSIX标准的要求。为了解决LinuxThread的缺陷,RedHat开发了一套符合POSIX标准的新型线程模型:NPTL(Native POSIX Thread Library)。关于Linuxthread与NPTL的比较,请参考文章:Linux 线程模型的比较:LinuxThreads 和 NPTL

二、Linux环境下的多线程编译支持

  按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令:

  1. gcc -D -REENTRANT -lpthread xxx. c

  其中-REENTRANT宏使得相关库函数(如stdio.h、errno.h中函数) 是可重入的、线程安全的(thread-safe),-lpthread则意味着链接库目录下的libpthread.a或libpthread.so文件。  

  在一个多线程程序里,默认情况下,只有一个errno变量供所有的线程共享。在一个线程准备获取刚才的错误代码时,该变量很容易被另一个线程中的函数调用所改变。类似的问题还存在于fputs之类的函数中,这些函数通常用一个单独的全局性区域来缓存输出数据。

为解决这个问题,需要使用可重入的例程。可重入代码可以被多次调用而仍然工作正常。编写的多线程程序,通过定义宏_REENTRANT来告诉编译器我们需要可重入功能,这个宏的定义必须出现于程序中的任何#include语句之前。

_REENTRANT为我们做三件事情,并且做的非常优雅:

(1)它会对部分函数重新定义它们的可安全重入的版本,这些函数名字一般不会发生改变,只是会在函数名后面添加_r字符串,如函数名gethostbyname变成gethostbyname_r。

(2)stdio.h中原来以宏的形式实现的一些函数将变成可安全重入函数。

(3)在error.h中定义的变量error现在将成为一个函数调用,它能够以一种安全的多线程方式来获取真正的errno的值。

三、Linux环境下的多线程函数

 3.1 线程创建

  在进程被创建时,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create函数:

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

  参数说明:

  • thread:指向pthread_create类型的指针,用于引用新创建的线程。
  • attr:用于设置线程的属性,一般不需要特殊的属性,所以可以简单地设置为NULL。
  • start_routine:传递新线程所要执行的函数地址。
  • arg:新线程所要执行的函数的参数。

  返回值:

  调用如果成功,则返回值是0;如果失败则返回错误代码。

  每个线程都有自己的线程ID,以便在进程内区分。线程ID在pthread_create调用时回返给创建线程的调用者;一个线程也可以在创建后使用pthread_self()调用获取自己的线程ID:

  1. pthread_self (void);

3.2 线程退出

  线程的退出方式有三种:

(1)执行完成后隐式退出;

(2)由线程本身显示调用pthread_exit 函数退出;

  1. pthread_exit (void * retval);

(3)被其他线程用pthread_cance函数终止:

  1. pthread_cancel (pthread_t thread);

  如果一个线程要等待另一个线程的终止,可以使用pthread_join函数,该函数的作用是调用pthread_join的线程将被挂起直到线程ID为参数thread的线程终止:

  1. pthread_join (pthread_t thread, void** threadreturn);

3.3 简单的多线程示例

  一个简单的Linux多线程示例如下:

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. void *thread_function(void *arg);
  7.  
  8. char message[] = "Hello World";
  9.  
  10. int main()
  11. {
  12. int res;
  13. pthread_t a_thread;
  14. void *thread_result;
  15.  
  16. res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
  17. if (res != )
  18. {
  19. perror("Thread creation failed!");
  20. exit(EXIT_FAILURE);
  21. }
  22.  
  23. printf("Waiting for thread to finish.../n");
  24.  
  25. res = pthread_join(a_thread, &thread_result);
  26. if (res != )
  27. {
  28. perror("Thread join failed!/n");
  29. exit(EXIT_FAILURE);
  30. }
  31.  
  32. printf("Thread joined, it returned %s/n", (char *)thread_result);
  33. printf("Message is now %s/n", message);
  34.  
  35. exit(EXIT_FAILURE);
  36. }
  37.  
  38. void *thread_function(void *arg)
  39. {
  40. printf("thread_function is running. Argument was %s/n", (char *)arg);
  41. sleep();
  42. strcpy(message, "Bye!");
  43. pthread_exit("Thank you for your CPU time!");
  44. }

  编译语句如下:

  1. gcc -D_REENTRANT thread1.c -o thread1 lpthread

  输出结果是:

  1. $./thread1[输出]:
  2. thread_function is running. Argument was Hello World
  3. Waiting for thread to finish...
  4. Thread joined, it returned Thank you for your CPU time!
  5. Message is now Bye!

  在这个例子中,pthread_exit(void *retval)本身返回的就是指向某个对象的指针,因此,pthread_join(pthread_t th, void **thread_return);中的thread_return是二级指针,指向线程返回值的指针。可以看到,我们创建的新线程修改的数组message的值,而原先的线程也可以访问该数组。如果我们调用的是fork而不是pthread_create,就不会有这样的效果了。因为fork创建子进程之后,子进程会拷贝父进程,两者分离,相互不干扰,而线程之间则是共享进程的相关资源。

小结:

  本文主要讲了Linux环境下的多线程基本概念,包括多线程的实现方式、函数接口、功能特性等。

多线程编程之Linux环境下的多线程(一)的更多相关文章

  1. 多线程编程之Linux环境下的多线程(三)

    前面两篇文章都讲述了Linux环境下的多线程编程基础知识,也附带了典型实例.本文主要比较一下Linux环境与Windows环境下的多线程编程区别. 看待技术问题要瞄准其本质,不管是WIN32.Linu ...

  2. 多线程编程之Linux环境下的多线程(二)

    上一篇文章中主要讲解了Linux环境下多线程的基本概念和特性,本文将说明Linux环境下多线程的同步方式. 在<UNIX环境高级编程>第二版的“第11章 线程”中,提到了类UNIX系统中的 ...

  3. 多线程编程之Windows环境下创建新线程

    转自: http://www.cnblogs.com/lgxqf/archive/2009/02/10/1387480.html 在 Win32 API 中,创建线程的基本函数是 CreateThre ...

  4. Linux环境下的多线程

    1. 按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令: gcc -D ...

  5. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  6. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  7. [转]c++多线程编程之pthread线程深入理解

    多线程编程之pthread线程深入理解         Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一 ...

  8. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  9. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

随机推荐

  1. 不错的nginx文章,找个时间好好看下。

    http://blog.csdn.net/chosen0ne/article/category/915324

  2. Ubuntu安装Sun JDK及如何设置默认java JDK

    假设系统为Ubuntu 10.10 64位.    先来看看当前的系统默认的java版本,及提供商.通过命令java -version       kemix@kemix-VB10-64:~$ jav ...

  3. Optimizing shaper — hashing filters (HTB)

    I have a very nice shaper in my linux box :-) How the configurator works — it’s another question, he ...

  4. jellyfish K-mer analysis and genome size estimate

    http://www.cbcb.umd.edu/software/jellyfish/   http://www.genome.umd.edu/jellyfish.html https://githu ...

  5. telnet命令使用示例

    导读 telnet命令通常用来远程登录.telnet程序是基于TELNET协议的远程登录客户端程序.Telnet协议是TCP/IP协议族中的一员,是Internet远程登录服务的标准协议和主要方式.它 ...

  6. yii2数据修改|联查

    model 层   联查 $con = Yii::$app->db; $re = $con->createCommand("select * from ads LEFT JOIN ...

  7. jquery商城购物车右侧悬浮加入购物车动画效果

    <script type="text/javascript" src="js/jquery-1.7.min.js"></script> ...

  8. Mvc3.0_笔记

    1.保留文本框中的值:<p>Find @Html.TextBox("searchKey", ViewBag.Filter as string)</p>  这 ...

  9. ztong上机3

    二.实验名称:数字图像处理matlab上机 三.实验学时:2学时 四.实验目的:(详细填写) 掌握几何变换 掌握插值 理解配准的概念 五.实验内容 (1)首先自己写一个对图像进行旋转和缩放的复合变换程 ...

  10. zf2 中 new Express 的用法

    在使用联表查询时,如查联表条件有多个也可以,但是连接条件在zf2中会自动给列加``符号,所以要加像id = 1 这样的,他自动给1加``就无示执行了,这时候可以使用new Express(''),他里 ...