Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7919052
  • 博文数量: 701
  • 博客积分: 2150
  • 博客等级: 上尉
  • 技术积分: 13233
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-29 16:28
个人简介

天行健,君子以自强不息!

文章分类

全部博文(701)

文章存档

2019年(2)

2018年(12)

2017年(76)

2016年(120)

2015年(178)

2014年(129)

2013年(123)

2012年(61)

分类: LINUX

2012-12-11 20:57:11

一、什么是线程
在一个程序中的多个执行路线就叫做线程(thread)。
更准确的定义是:
线程是一个进程内部的一个控制序列。
事实上,所有的进程都至少有一个执行线程。

创建新进程的fork系统调用与创建新线程的区别:
当进程执行fork调用时,
    将创建出该进程的一份新副本。
    这个新进程拥有自己的变量和自己的PID,
    它的时间调度也是独立的,
    它的执行(通常)几乎是完全独立于父进程。
当在进程中创建一个新线程时,
    新的线程拥有自己的栈,
    因此也有自己的局部变量,
    但它与创建者共享全局变量、文件描述符、信号处理函数和当前目录状态。

二、线程的优点和缺点
线程的优点:
A. 可以让程序在同时做多件事情;
   如编辑文档的同时对文档的单词个进行实时统计。
B. 一个混杂着输入、计算和输出的应用程序,
   可以将这几个部分分离为3个线程来执行,从而改善程序执行的性能。
   一个需要同时处理多个网络连接的服务器应用程序天生适应于多线程。
C. 线程之间的切换需要操作系统做的工作比进程之间的切换少得多,
   因此,多个线程对资源的需求要远小于多个进程。

线程的缺点:
A. 多线程需要非常仔细的设计,
   变量共享的引入很容易引发错误。
B. 多线程程序的调试要比单线程程序的调试困难得多,
   线程间的交互也很难控制。
C. 将大量计算分成两个部分,
   并以不同的线程在一台单处理器上运行并不一定更快;
   除非这个计算是真正独立且机器支持多核多处理。

三、线程函数
线程有一套完整的与其有关的函数库调用,
它们中的绝大多数函数名都以pthread开头。
为了使用这些函数库调用,需要:
A. 在编译时定义宏 _REENTRANT,
   用来告诉编译器程序需要可重入功能,
   这个宏的定义必须位于程序中的任何#include语句之前,即在编译时用。
   它将做三件事:
   a. 对部分函数重新定义它们的可安全重入的版本,
      这些函数的名字一般不会发生改变,只是会在函数名后添加"_r"字符串。
      例如,函数名gethostbyname将变为gethostbyname_r。
   b. stdio.h中原来以宏的形式实现的一些函数将变成可安全重入的函数。
   c. 在errno.h中定义的变量errno现在将成为一个函数调用,
      它能够以一种多线程安全的方式来获取真正的errno值。
B. 在程序中包含头文件pthread.h
C. 在编译时添加选项-lpthread链接线程库。

线程函数
  1. #include <pthread.h>

  2. int pthread_create(pthread_t *thread, pthread_attr_t *attr,
  3.                    void *(*start_routine)(void *), void *arg);
创建一个新线程;

参数:
thread: 指向pthread_t类型数据的指针。
        线程被创建时,这个指针指向的变量中将被写入一个标识符,
        用来引用这个新线程。
attr  : 设置线程的属性,通常可以设为NULL。
strart_routine: 将要启动执行的函数。
void *(*start_routine)(void *):
        函数指针,
        该函数以一个指向void的指针为参数,
        返回的也是一个指向void的指针。
        因此,可以传递一个任一类型的参数并返回一个任一类型的指针。
arg   : 传递给执行函数的参数。



  1. #include <pthread.h>

  2. void pthread_exit(void *retval);
线程通过调用pthread_exit函数终止执行。
这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
注意: 绝不能用它来返回一个指向局部变量的指针。
      因为线程调用该函数后,这个局部变量就不存在了。



  1. #include <pthread.h>

  2. int pthread_join(pthread_t th, void **thread_return);
等待线程的结束。
参数:
th  : 要等待的线程。
thread_return: 指向线程的返回值。

返回值:
上述函数都是,
成功时,返回0;
失败时,返回错误代码。

四、初步程序设计
这个程序创建了一个新线程,
新线程与原先的线程共享变量,
并在结束时向原先的线程返回一个结果。
thread1.c
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>

  5. #include <pthread.h>

  6. void *thread_function(void *arg);

  7. char message[] = "Hello World";

  8. int main()
  9. {
  10.   int res;
  11.   pthread_t a_thread;
  12.   void *thread_result;

  13.   res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
  14.   if (res != 0)
  15.   {
  16.     perror("Thread creation failed");
  17.     exit(EXIT_FAILURE);
  18.   }

  19.   printf("Waiting for thread to finish...\n");
  20.   res = pthread_join(a_thread, &thread_result);
  21.   if (res != 0)
  22.   {
  23.     perror("Thread join failed");
  24.     exit(EXIT_FAILURE);
  25.   }

  26.   printf("Thread joined, it returned %s\n", (char *)thread_result);
  27.   printf("Message is now %s\n", message);
  28.   exit(EXIT_SUCCESS);
  29. }

  30. void *thread_function(void *arg)
  31. {
  32.   /* 使用参数 arg */
  33.   printf("thread_function is running. Argument was %s\n", (char *)arg);
  34.   sleep(3);

  35.   /* 直接修改全局变量message */
  36.   strcpy(message, "Bye!");

  37.   /* 设置线程返回值 */
  38.   pthread_exit("Thank you for the CPU time");
  39. }

编译:
  1. $ cc -D_REENTRANT thread1.c –o thread1 -lpthread

运行:
  1. $ ./thread1
  2. Waiting for thread to finish...
  3. thread_function is running. Argument was Hello World
  4. Thread joined, it returned Thank you for the CPU time
  5. Message is now

阅读(2792) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~