Linux下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,链接时需要使用库libpthread.a。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但是它可与同属一个进程的其它的线程共享进程所拥有的全部资源。当多个任务可以并行执行时,可以为每个任务启动一个线程。
线程是并发运行的。在串行程序基础上引入线程和进程是为了提供程序的并发度,从而提高程序运行效率和响应时间。
与进程相比,线程的优势:(1)、线程共享相同的内存空间,不同的线程可以存取内存中的同一个变量;(2)、与标准fork()相比,线程带来的开销很小,节省了CPU时间,使得线程创建比新进程创建快上十到一百倍。
适应多线程的理由:(1)、和进程相比,它是一种非常“节俭”的多任务操作方式,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种“昂贵”的多任务工作方式。而运行一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间;(2)、线程间方便的通信机制。对不同的进程来说,它们具有独立的数据空间,要进行数据的传输只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
多线程程序作为一种多任务、并发的工作方式,其优点包括:(1)、提供应用程序响应;(2)、使多CPU系统更加有效:操作系统会保证当线程数不大于CPU数目时,不同的线程运行在不同的CPU上;(3)、改善程序结构:一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序利于理解和修改。
pthread_create:用于在调用的进程中创建一个新的线程。它有四个参数,第一个参数为指向线程标识符指针;第二个参数用来设置线程属性;第三个参数是线程运行函数的起始地址;第四个参数是运行函数的参数。
在一个线程中调用pthread_create函数创建新的线程后,当前线程从pthread_create处继续往下执行。pthread_create函数的第三个参数为新创建线程的入口函数的起始地址,此函数接收一个参数,是通过第四个参数传递给它的,该参数的类型是void*,这个指针按什么类型解释由调用者自己定义,入口函数的返回值类型也是void*,这个指针的含义同样由调用者自己定义,入口函数返回时,这个线程就退出了,其它线程可以调用pthread_join函数得到入口函数的返回值。
pthread_join:线程阻塞函数,用于阻塞当前的线程,直到另外一个线程运行结束;使一个线程等待另一个线程结束;让主线程阻塞在这个地方等待子线程结束;代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了,加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。
pthread_create将一个线程拆分为两个,pthread_join()将两个线程合并为一个线程。
一个线程实际上就是一个函数,创建后,立即被执行,当函数返回时该线程也就结束了。
线程终止时,一个需要注意的问题是线程间的同步问题。一般情况下,进程中各个线程的运行是相互独立的,线程的终止并不会相互通知,也不会影响其它线程,终止的线程所占用的资源不会随着线程的终止而归还系统,而是仍然为线程所在的进程持有。一个线程仅允许一个线程使用pthread_join等待它的终止,并且被等待的线程应该处于可join状态,而非DETACHED状态。一个可”join”的线程所占用的内存仅当有线程对其执行了pthread_join()后才会释放,因此为了避免内存泄露,所有线程终止时,要么设为DETACHED,要么使用pthread_join来回收资源。一个线程不能被多个线程等待。
所有线程都有一个线程号,也就是threadid,其类型为pthread_t,通过调用pthread_self函数可以获得自身的线程号。
Linux线程同步的几种基本方式:join、互斥锁(mutex)、读写锁(read-writelock)、条件变量(condition variables)。mutex的本质是锁,而条件变量的本质是等待。