1. 基本概念
1)线程就是程序的执行路线,即进程内部的控制序列,或者说是进程的子任务。
2)线程,轻量级,不拥有自己独立的内存资源,共享进程的代码区、数据区、堆区(注意没有栈区)、
环境变量和命令行参数、文件描述符、信号处理函数、当前目录、用户 ID 和组 ID 等资源。
3)线程拥有自己独立的栈,因此也有自己独立的局部变量。
4)一个进程可以同时拥有多个线程,即同时被系统调度的多条执行路线,但至少要有一个主线程。
线程是调度的基本单位;进程是资源分配的基本单位;
2. 基本特点
1)线程是进程的一个实体,可作为系统独立调度和分派的基本单位。
2)线程有不同的状态,系统提供了多种线程控制原语,如创建线程、销毁线程等等。
3)线程不拥有自己的资源,只拥有从属于进程的全部资源,所有的资源分配都是面向进程的。
4)一个进程中可以有多个线程并发地运行;它们可以执行相同的代码,也可以执行不同的代码。
5)同一个进程的多个线程都在同一个地址空间内活动,因此相对于进程,线程的系统开销小,任务切换快。
6)线程间的数据交换不需要依赖于类似 IPC 的特殊通信机制,简单而高效。
7)每个线程拥有自己独立的线程 ID、寄存器信息、函数栈、错误码和信号掩码。
8)线程之间存在优先级的差异。
3. POSIX 线程 (pthread)
1)早期厂商各自提供私有的线程库版本,接口和实现的差异非常大,不易于移植。
2)IEEE POSIX 1003.1c (1995) 标准,定义了统一的线程编程接口,
遵循该标准的线程实现被统称为 POSIX 线程,即 pthread。
3)pthread 包含一个头文件 pthread.h,和一个接口库 libpthread.so。
#include <pthread.h>
. . .
# gcc ... -lpthread
4)功能
线程管理:创建/销毁线程、分离/联合线程、设置/查询线程属性。
线程同步:
A. 互斥量:创建/销毁互斥量、加锁/解锁互斥量、设置/查询互斥量属性。
B. 条件变量:创建/销毁条件变量、等待/触发条件变量、设置/查询条件变量属性。
4. 线程函数
创建线程
====
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* restrict attr,
void* (*start_routine) (void*), void* restrict arg);
thread - 线程 ID,输出参数。
pthread_t 即 unsigned long int。
attr - 线程属性,NULL 表示缺省属性。
pthread_attr_t 可能是整型也可能是结构,因实现而异。
start_routine - 线程过程函数指针,参数和返回值的类型都是 void*。
启动线程本质上就是调用一个函数,只不过是在一个独立的线程中调用的,函数返回即线程结束。
arg - 传递给线程过程函数的参数。
线程过程函数的调用者是系统内核,而非用户代码,因此需要在创建线程时指定参数。
成功返回 0,失败返回错误码。
注意:
1) restrict: C99 引入的编译优化指示符,提高重复解引用同一个指针的效率。
2) 在 pthread.h 头文件中声明的函数,通常以直接返回错误码的方式表示失败,而非以错误码设置 errno 并返回 -1。
3) main 函数即主线程,main 函数返回即主线程结束,主线程结束即进程结束,进程一但结束其所有的线程即结束。
4) 应设法保证在线程过程函数执行期间,其参数所指向的目标持久有效。
创建线程;范例:create.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
printf ("%lu线程:%s\n", pthread_self (), (char*)arg);
return NULL;
}
int main (void) {
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, "我是快乐的子线程!");
if (error) {
// 这里打印错误,不能用 perror 或者 \m
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
printf ("%lu线程:我是主线程,创建了%lu线程。\n", pthread_self (), tid);
sleep (1);
return 0;
}
线程并发;范例:concur.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
size_t i;
for (i = 0; i < 500; i++) {
printf ("%*d\n", ((size_t)arg + 1) * 4, i + 1);
usleep (50000);
}
return NULL;
}
int main (void) {
pthread_t tids[20];
size_t i;
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_create (&tids[i], NULL, thread_proc, (void*)i);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
}
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_join (tids[i], NULL);
if (error) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
}
return 0;
}
线程参数;范例:arg.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
*(double*)arg = PAI * r * r;
return NULL;
}
typedef struct tag_Pyth {
double a;
double b;
double c;
} PYTH, *LPPYTH;
void* thread_pyth (void* arg) {
LPPYTH pyth = (LPPYTH)arg;
pyth -> c = sqrt (pyth -> a * pyth -> a + pyth -> b * pyth -> b);
return NULL;
}
void* thread_aver (void* arg) {
double* d = (double*)arg;
d[2] = (d[0] + d[1]) / 2;
return NULL;
}
void* thread_show (void* arg) {
sleep (1);
printf ("n = %d\n", *(int*)arg);
return NULL;
}
int main (void) {
printf ("r = ");
1)线程就是程序的执行路线,即进程内部的控制序列,或者说是进程的子任务。
2)线程,轻量级,不拥有自己独立的内存资源,共享进程的代码区、数据区、堆区(注意没有栈区)、
环境变量和命令行参数、文件描述符、信号处理函数、当前目录、用户 ID 和组 ID 等资源。
3)线程拥有自己独立的栈,因此也有自己独立的局部变量。
4)一个进程可以同时拥有多个线程,即同时被系统调度的多条执行路线,但至少要有一个主线程。
线程是调度的基本单位;进程是资源分配的基本单位;
2. 基本特点
1)线程是进程的一个实体,可作为系统独立调度和分派的基本单位。
2)线程有不同的状态,系统提供了多种线程控制原语,如创建线程、销毁线程等等。
3)线程不拥有自己的资源,只拥有从属于进程的全部资源,所有的资源分配都是面向进程的。
4)一个进程中可以有多个线程并发地运行;它们可以执行相同的代码,也可以执行不同的代码。
5)同一个进程的多个线程都在同一个地址空间内活动,因此相对于进程,线程的系统开销小,任务切换快。
6)线程间的数据交换不需要依赖于类似 IPC 的特殊通信机制,简单而高效。
7)每个线程拥有自己独立的线程 ID、寄存器信息、函数栈、错误码和信号掩码。
8)线程之间存在优先级的差异。
3. POSIX 线程 (pthread)
1)早期厂商各自提供私有的线程库版本,接口和实现的差异非常大,不易于移植。
2)IEEE POSIX 1003.1c (1995) 标准,定义了统一的线程编程接口,
遵循该标准的线程实现被统称为 POSIX 线程,即 pthread。
3)pthread 包含一个头文件 pthread.h,和一个接口库 libpthread.so。
#include <pthread.h>
. . .
# gcc ... -lpthread
4)功能
线程管理:创建/销毁线程、分离/联合线程、设置/查询线程属性。
线程同步:
A. 互斥量:创建/销毁互斥量、加锁/解锁互斥量、设置/查询互斥量属性。
B. 条件变量:创建/销毁条件变量、等待/触发条件变量、设置/查询条件变量属性。
4. 线程函数
创建线程
====
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* restrict attr,
void* (*start_routine) (void*), void* restrict arg);
thread - 线程 ID,输出参数。
pthread_t 即 unsigned long int。
attr - 线程属性,NULL 表示缺省属性。
pthread_attr_t 可能是整型也可能是结构,因实现而异。
start_routine - 线程过程函数指针,参数和返回值的类型都是 void*。
启动线程本质上就是调用一个函数,只不过是在一个独立的线程中调用的,函数返回即线程结束。
arg - 传递给线程过程函数的参数。
线程过程函数的调用者是系统内核,而非用户代码,因此需要在创建线程时指定参数。
成功返回 0,失败返回错误码。
注意:
1) restrict: C99 引入的编译优化指示符,提高重复解引用同一个指针的效率。
2) 在 pthread.h 头文件中声明的函数,通常以直接返回错误码的方式表示失败,而非以错误码设置 errno 并返回 -1。
3) main 函数即主线程,main 函数返回即主线程结束,主线程结束即进程结束,进程一但结束其所有的线程即结束。
4) 应设法保证在线程过程函数执行期间,其参数所指向的目标持久有效。
创建线程;范例:create.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
printf ("%lu线程:%s\n", pthread_self (), (char*)arg);
return NULL;
}
int main (void) {
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, "我是快乐的子线程!");
if (error) {
// 这里打印错误,不能用 perror 或者 \m
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
printf ("%lu线程:我是主线程,创建了%lu线程。\n", pthread_self (), tid);
sleep (1);
return 0;
}
线程并发;范例:concur.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
size_t i;
for (i = 0; i < 500; i++) {
printf ("%*d\n", ((size_t)arg + 1) * 4, i + 1);
usleep (50000);
}
return NULL;
}
int main (void) {
pthread_t tids[20];
size_t i;
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_create (&tids[i], NULL, thread_proc, (void*)i);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
}
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_join (tids[i], NULL);
if (error) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
}
return 0;
}
线程参数;范例:arg.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
*(double*)arg = PAI * r * r;
return NULL;
}
typedef struct tag_Pyth {
double a;
double b;
double c;
} PYTH, *LPPYTH;
void* thread_pyth (void* arg) {
LPPYTH pyth = (LPPYTH)arg;
pyth -> c = sqrt (pyth -> a * pyth -> a + pyth -> b * pyth -> b);
return NULL;
}
void* thread_aver (void* arg) {
double* d = (double*)arg;
d[2] = (d[0] + d[1]) / 2;
return NULL;
}
void* thread_show (void* arg) {
sleep (1);
printf ("n = %d\n", *(int*)arg);
return NULL;
}
int main (void) {
printf ("r = ");