线程是一个进程中的控制和执行单元,也是 CPU 调度和分派的基本单元。在传统的 UNIX 系统中,一个进程只有一个线程(主线程),即在同一时刻只能做一件事情。在现代的 UNIX 系统中,一个进程可以包含多个线程,每个线程处理各自独立的任务,称之为“并发(concurrency)”,但并不等同于“并行(parallelism)”。真正意义上的并行只存在于多处理器系统中,而并发也可以存在于单处理器中。并行要求程序能够同时执行多个操作,而并发只要求程序能够假装同时执行多个操作,处理器的数量并不影响程序结构。
进程是系统中程序执行和资源分配的基本单位,每个进程有自己的数据段、代码段和堆栈段。在进程中可以创建多个线程, 并发地完成多个不同的任务。线程各自有独自的线程ID、寄存器值、栈、调度优先级和策略、信号屏蔽字、errno 变量以及线程私有数据,而进程的可执行的程序文本、全局内存和堆内存、栈以及文件描述符对该进程的所有线程都是共享的。线程与进程之间的关系可由下图表示:
多线程优点:
多线程缺点:
每个线程都有一个线程ID,线程ID只在它所属的进程环境中有效。线程ID使用 pthread_t 数据类型来表示,实现的时候可以使用一个结构来表示 pthread_t 数据类型,所以可移植的操作系统实现不能将它比作整数处理,因此必须使用 pthread_equal 函数来对比线程ID进行比较。 线程可以通过调用pthread_self 函数获得自身线程ID。
/* 线程 */ /* * 函数功能:比较两个线程ID; * 返回值:若相等则返回非0,否则返回0; * 函数原型: */ #include <pthread.h> int pthread_equal(pthread_t tid1, pthread_t tid2); /* * 函数功能:获取自身的线程ID; * 返回值:调用线程的线程ID; * 函数原型: */ pthread_t pthread_self(void);
线程可以通过调用 pthread_create 函数创建。线程创建时并不能保证哪个线程会先运行,新创建的线程可以访问进程的地址空间,并且继承调用点成的浮点环境和信号屏蔽字,但是该线程的未决信号集被清除。在当前线程从函数pthread_create 中返回以及新线程被调度执行之间不存在同步关系,即新线程可能在当前线程从pthread_create 返回之前就运行了。甚至在 pthread_create 返回之前,新线程就可能已经运行完毕了。
/* * 函数功能:创建线程; * 返回值:若成功则返回0,否则返回错误编号; * 函数原型: */ int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg); /* * 说明: * 当该函数成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID; * attr参数用于定制各种不同的线程属性,当为NULL表示创建默认属性的线程; * 新创建的线程从start_rtn函数的地址开始运行,该函数只有一个指针参数arg, * 如果需要向start_rtn函数传递的参数不止一个,则需要把参数放在一个结构中, * 然后把这个结构的地址作为arg参数传入; */测试程序:
#include "apue.h" #include <pthread.h> pthread_t ntid; static void printids(const char *); static void *func(void*); int main(void) { int err; err = pthread_create(&ntid, NULL, func, NULL); if(err != 0) err_quit("can't create thread: %s\n",strerror(err)); printids("main thread: "); sleep(1); exit(0); } static void printids(const char *s) { pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,(unsigned int)tid,(unsigned int)tid); } static void *func(void *arg) { printids("new thread: "); return((void*)0); }输出结果:
main thread: pid 4156 tid 3076343488 (0xb75d46c0) new thread: pid 4156 tid 3076340544 (0xb75d3b40)
该程序实现的功能是在当前进程新建线程,并打印出主线程和新建线程的线程ID以及进程的ID,从结果可以知道,这两个线程在同一个进程中;注意:在 Linux下编译线程程序是必须加上 -lpthread 参数,因为 pthread 库不是Linux 系统默认的库,连接时需要使用库libpthread.a。编译过程:
gcc pthreadtest.c -o thread -lpthread
《UNIX高级环境编程》