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 = ");
double rs;
scanf ("%lf", &rs);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &rs);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) { // pthread_join 参见下面
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", rs);
PYTH pyth;
printf ("a = ");
scanf ("%lf", &pyth.a);
printf ("b = ");
scanf ("%lf", &pyth.b);
if ((error = pthread_create (&tid, NULL, thread_pyth, &pyth)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("c = %g\n", pyth.c);
double d[3];
printf ("x = ");
scanf ("%lf", &d[0]);
printf ("y = ");
scanf ("%lf", &d[1]);
if ((error = pthread_create (&tid, NULL, thread_aver, d)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("z = %g\n", d[2]);
int* n = malloc (sizeof (int));
*n = 1234;
if ((error = pthread_create (&tid, NULL, thread_show, n)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
/*
free (n);
*/
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
free (n);
return 0;
}
等待线程
====
int pthread_join (pthread_t thread, void** retval);
等待 thread 参数所标识的线程结束,成功返回 0,失败返回错误码。
范例:ret.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
/*
static double s;
s = PAI * r * r;
return &s;
*/
double* s = malloc (sizeof (double));
*s = PAI * r * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
注意从线程过程函数中返回值的方法:
1) 线程过程函数将所需返回的内容放在一块内存中,
返回该内存的地址,保证这块内存在函数返回,即线程结束,以后依然有效;
2) 若 retval 参数非 NULL,则 pthread_join 函数将线程过程函数所返回的指针,
拷贝到该参数所指向的内存中;
3) 若线程过程函数所返回的指针指向动态分配的内存,
则还需保证在用过该内存之后释放之。
获取线程自身的 ID
=========
pthread_t pthread_self (void);
成功返回调用线程的 ID,不会失败。
比较两个线程的 ID
=========
int pthread_equal (pthread_t t1, pthread_t t2);
若参数 t1 和 t2 所标识的线程 ID 相等,则返回非零,否则返回 0。
某些实现的 pthread_t 不是 unsigned long int 类型,
可能是结构体类型,无法通过“==”判断其相等性。
范例:equal.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_t g_main;
void* ismain (void* arg) {
// if (pthread_self () == g_main)
if (pthread_equal (pthread_self (), g_main))
printf ("我是主线程!\n");
else
printf ("我不是主线程!\n");
return NULL;
}
int main (void) {
g_main = pthread_self ()
ismain (NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, ismain, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
return 0;
}
终止线程
====
1) 从线程过程函数中 return。
2) 调用 pthread_exit 函数。
void pthread_exit (void* retval);
retval - 和线程过程函数的返回值语义相同。
注意:在任何线程中调用 exit 函数都将终止整个进程。
范例:exit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
double* s = malloc (sizeof (double));
// exit (0);
*s = PAI * r * r;
pthread_exit (s); // <==> return s;
*s = 2 * PAI * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
线程执行轨迹
======
1) 同步方式 (非分离状态):
创建线程之后调用 pthread_join 函数等待其终止,并释放线程资源。
2) 异步方式 (分离状态):
无需创建者等待,线程终止后自行释放资源。
int pthread_detach (pthread_t thread);
使 thread 参数所标识的线程进入分离 (DETACHED) 状态。
处于分离状态的线程终止后自动释放线程资源,且不能被 pthread_join 函数等待。
成功返回 0,失败返回错误码。
范例:detach.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
int i;
for (i = 0; i < 200; i++) {
putchar ('-');
usleep (50000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
// pthread_detach () 写在 thread_proc () 里面依然会被 pthread_join () 捕获,无效果;
if ((error = pthread_detach (tid)) != 0) {
fprintf (stderr, "pthread_detach: %s\n", strerror (error));
return -1;
}
/*
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
*/
int i;
for (i = 0; i < 200; i++) {
putchar ('+');
usleep (100000);
}
printf ("\n");
return 0;
}
取消线程
====
1) 向指定线程发送取消请求
int pthread_cancel (pthread_t thread);
成功返回 0,失败返回错误码。
注意:该函数只是向线程发出取消请求,并不等待线程终止。
缺省情况下,线程在收到取消请求以后,并不会立即终止,而是仍继续运行,直到其达到某个取消点。
在取消点处,线程检查其自身是否已被取消了,并做出相应动作。
当线程调用一些特定函数时,取消点会出现。
2) 设置调用线程的可取消状态
int pthread_setcancelstate (int state, int* oldstate);
成功返回 0,并通过 oldstate 参数输出原可取消状态
(若非 NULL),失败返回错误码。
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消请求 (缺省)。
PTHREAD_CANCEL_DISABLE - 忽略取消请求。
3) 设置调用线程的可取消类型
int pthread_setcanceltype (int type, int* oldtype);
成功返回 0,并通过 oldtype 参数输出原可取消类型
(若非 NULL),失败返回错误码。
type取值:
PTHREAD_CANCEL_DEFERRED - 延迟取消(缺省)。
被取消线程在接收到取消请求之后并不立即响应,
而是一直等到执行了特定的函数(取消点)之后再响应该请求。
PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消。
被取消线程可以在任意时间取消,不是非得遇到取消点才能被取消。
但是操作系统并不能保证这一点。
范例:cancel.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void elapse (void) {
size_t i;
for (i = 0; i < 800000000; ++i);
}
void* thread_proc (void* arg) {
/*
int error = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
if (error) {
fprintf (stderr, "pthread_setcancelstate: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*//*
int error = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (error) {
fprintf (stderr, "pthread_setcanceltype: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*/
for (;;) {
printf ("线程:子在川上曰,逝者如斯夫。\n");
elapse ();
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
printf ("按<回车>取消线程...\n");
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
getchar ();
if ((error = pthread_cancel (tid)) != 0) {
fprintf (stderr, "pthread_cancel: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
printf ("已发送取消请求,等待线程终止...\n");
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("线程已终止。\n");
return 0;
}
线程属性
====
创建线程函数
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* restrict attr,
void* (*start_routine) (void*), void* restrict arg);
第二个参数即为线程属性,传空指针表示使用缺省属性。
typedef struct {
/* 分离状态 :
PTHREAD_CREATE_DETACHED - 分离线程。
PTHREAD_CREATE_JOINABLE(缺省) - 可汇合线程。
*/
int detachstate;
/* 竞争范围 :
PTHREAD_SCOPE_SYSTEM - 在系统范围内竞争资源。
PTHREAD_SCOPE_PROCESS(Linux不支持) - 在进程范围内竞争资源。
*/
int scope;
/* 继承特性 :
PTHREAD_INHERIT_SCHED(缺省) - 调度属性自创建者线程继承。
PTHREAD_EXPLICIT_SCHED - 调度属性由后面两个成员确定。
*/
int inheritsched;
/* 调度策略 :
SCHED_FIFO - 先进先出策略。
没有时间片; 一个 FIFO 线程会持续运行,直到阻塞或有高优先级线程就绪。
当 FIFO 线程阻塞时,系统将其移出就绪队列,待其恢复时再加到同优先级就绪队列的末尾。
当 FIFO 线程被高优先级线程抢占时,它在就绪队列中的位置不变。
因此一旦高优先级线程终止或阻塞,被抢占的 FIFO 线程将会立即继续运行。
SCHED_RR - 轮转策略。
给每个 RR 线程分配一个时间片,一但 RR 线程的时间片耗尽,系统即将移到就绪队列的末尾。
SCHED_OTHER(缺省) - 普通策略。
静态优先级为 0。任何就绪的 FIFO 线程或 RR 线程,都会抢占此类线程。
*/
int schedpolicy;
/* 调度参数 :
struct sched_param {
int sched_priority; // 静态优先级
};
*/
struct sched_param schedparam;
// 栈尾警戒区大小 (字节),缺省一页 (4096字节)。
size_t guardsize;
// 栈地址
void* stackaddr;
// 栈大小 (字节)
size_t stacksize;
} pthread_attr_t;
不要手工读写该结构体,
而应调用 pthread_attr_set/get 函数设置/获取具体属性项。
1) 设置线程属性
第一步,初始化线程属性结构体
int pthread_attr_init (pthread_attr_t* attr);
第二步,设置具体线程属性项
int pthread_attr_setdetachstate (pthread_attr_t* attr, int detachstate);
int pthread_attr_setscope (pthread_attr_t* attr, int scope);
int pthread_attr_setinheritsched (pthread_attr_t* attr, int inheritsched);
int pthread_attr_setschedpolicy (pthread_attr_t* attr, int policy);
int pthread_attr_setschedparam (pthread_attr_t* attr, const struct sched_param* param);
int pthread_attr_setguardsize (pthread_attr_t* attr, size_t guardsize);
int pthread_attr_setstackaddr (pthread_attr_t* attr, void* stackaddr);
int pthread_attr_setstacksize (pthread_attr_t* attr, size_t stacksize);
int pthread_attr_setstack (pthread_attr_t* attr, void* stackaddr, size_t stacksize);
第三步,以设置好的线程属性结构体为参数创建线程
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* testrict attr,
void* (*start_routine) (void*), void* restrict arg);
第四步,销毁线程属性结构体
int pthread_attr_destroy (pthread_attr_t* attr);
2) 获取线程属性
第一步,获取线程属性结构体
int pthread_getattr_np (pthread_t thread, pthread_attr_t* attr);
第二步,获取具体线程属性项
int pthread_attr_getdetachstate (pthread_attr_t* attr, int* detachstate);
int pthread_attr_getscope (pthread_attr_t* attr, int* scope);
int pthread_attr_getinheritsched (pthread_attr_t* attr, int* inheritsched);
int pthread_attr_getschedpolicy (pthread_attr_t* attr, int* policy);
int pthread_attr_getschedparam (pthread_attr_t* attr, struct sched_param* param);
int pthread_attr_getguardsize (pthread_attr_t* attr, size_t* guardsize);
int pthread_attr_getstackaddr (pthread_attr_t* attr, void** stackaddr);
int pthread_attr_getstacksize (pthread_attr_t* attr, size_t* stacksize);
int pthread_attr_getstack (pthread_attr_t* attr, void** stackaddr, size_t* stacksize);
以上所有函数成功返回 0,失败返回错误码。
范例:attr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
int printattrs (pthread_attr_t* attr) {
printf("------- 线程属性 -------\n");
int detachstate;
int error = pthread_attr_getdetachstate (attr, &detachstate);
if (error) {
fprintf (stderr, "pthread_attr_getdetachstate: %s\n", strerror (error));
return -1;
}
printf("分离状态: %s\n",
(detachstate == PTHREAD_CREATE_DETACHED) ? "分离线程" :
(detachstate == PTHREAD_CREATE_JOINABLE) ? "可汇合线程" : "未知");
int scope;
if ((error = pthread_attr_getscope (attr, &scope)) != 0) {
fprintf (stderr, "pthread_attr_getscope: %s\n", strerror (error));
return -1;
}
printf ("竞争范围: %s\n",
(scope == PTHREAD_SCOPE_SYSTEM) ? "系统级竞争" :
(scope == PTHREAD_SCOPE_PROCESS) ? "进程级竞争" : "未知");
int inheritsched;
if ((error = pthread_attr_getinheritsched (attr, &inheritsched)) != 0) {
fprintf (stderr, "pthread_attr_getinheritsched: %s\n", strerror (error));
return -1;
}
printf ("继承特性: %s\n",
(inheritsched == PTHREAD_INHERIT_SCHED) ? "继承调用属性" :
(inheritsched == PTHREAD_EXPLICIT_SCHED) ? "显式调用属性" : "未知");
int schedpolicy;
if ((error = pthread_attr_getschedpolicy(attr, &schedpolicy)) != 0) {
fprintf (stderr, "pthread_attr_getschedpolicy: %s\n", strerror (error));
return -1;
}
printf ("调度策略: %s\n",
(schedpolicy == SCHED_OTHER) ? "普通" :
(schedpolicy == SCHED_FIFO) ? "先进先出" :
(schedpolicy == SCHED_RR) ? "轮转" : "未知");
struct sched_param schedparam;
if ((error = pthread_attr_getschedparam (attr, &schedparam)) != 0) {
fprintf (stderr, "pthread_attr_getschedparam: %s\n", strerror (error));
return -1;
}
printf ("调度优先级:%d\n", schedparam.sched_priority);
size_t guardsize;
if ((error = pthread_attr_getguardsize(attr, &guardsize)) != 0) {
fprintf (stderr, "pthread_attr_getguardsize: %s\n", strerror (error));
return -1;
}
printf ("栈尾警戒区:%u字节\n", guardsize);
/*
void* stackaddr;
if ((error = pthread_attr_getstackaddr (attr, &stackaddr)) != 0) {
fprintf (stderr, "pthread_attr_getstackaddr: %s\n", strerror (error));
return -1;
}
printf ("栈地址: %p\n", stackaddr);
size_t stacksize;
if ((error = pthread_attr_getstacksize (attr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstacksize: %s\n", strerror (error));
return -1;
}
printf ("栈大小: %u字节\n", stacksize);
*/
void* stackaddr;
size_t stacksize;
if ((error = pthread_attr_getstack (attr, &stackaddr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstack: %s\n", strerror (error));
return -1;
}
printf ("栈地址: %p\n", stackaddr);
printf ("栈大小: %u字节\n", stacksize);
printf("------------------------\n");
return 0;
}
void* thread_proc (void* arg) {
pthread_attr_t attr;
int error = pthread_getattr_np (pthread_self (), &attr);
if (error) {
fprintf (stderr, "pthread_getattr_np: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
if (printattrs (&attr) < 0)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
return NULL;
}
int main (int argc, char* argv[]) {
int error;
pthread_attr_t attr, *pattr = NULL;
if (argc > 1) {
if (strcmp (argv[1], "-s")) {
fprintf (stderr, "用法:%s [-s]\n", argv[0]);
return -1;
}
if ((error = pthread_attr_init (&attr)) != 0) {
fprintf (stderr, "pthread_attr_init: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setdetachstate (&attr,
PTHREAD_CREATE_DETACHED)) != 0) {
fprintf (stderr, "pthread_attr_setdetachstate: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setinheritsched (&attr,
PTHREAD_EXPLICIT_SCHED)) != 0) {
fprintf (stderr, "pthread_attr_setinheritsched: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setstacksize (&attr, 4096*10)) != 0) {
fprintf (stderr, "pthread_attr_setstack: %s\n", strerror (error));
return -1;
}
pattr = &attr;
}
pthread_t tid;
if ((error = pthread_create (&tid, pattr, thread_proc, NULL)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if (pattr)
if ((error = pthread_attr_destroy (pattr)) != 0) {
fprintf (stderr, "pthread_attr_destroy: %s\n", strerror (error));
return -1;
}
pause ();
return 0;
}
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 = ");
double rs;
scanf ("%lf", &rs);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &rs);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) { // pthread_join 参见下面
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", rs);
PYTH pyth;
printf ("a = ");
scanf ("%lf", &pyth.a);
printf ("b = ");
scanf ("%lf", &pyth.b);
if ((error = pthread_create (&tid, NULL, thread_pyth, &pyth)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("c = %g\n", pyth.c);
double d[3];
printf ("x = ");
scanf ("%lf", &d[0]);
printf ("y = ");
scanf ("%lf", &d[1]);
if ((error = pthread_create (&tid, NULL, thread_aver, d)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("z = %g\n", d[2]);
int* n = malloc (sizeof (int));
*n = 1234;
if ((error = pthread_create (&tid, NULL, thread_show, n)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
/*
free (n);
*/
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
free (n);
return 0;
}
等待线程
====
int pthread_join (pthread_t thread, void** retval);
等待 thread 参数所标识的线程结束,成功返回 0,失败返回错误码。
范例:ret.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
/*
static double s;
s = PAI * r * r;
return &s;
*/
double* s = malloc (sizeof (double));
*s = PAI * r * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
注意从线程过程函数中返回值的方法:
1) 线程过程函数将所需返回的内容放在一块内存中,
返回该内存的地址,保证这块内存在函数返回,即线程结束,以后依然有效;
2) 若 retval 参数非 NULL,则 pthread_join 函数将线程过程函数所返回的指针,
拷贝到该参数所指向的内存中;
3) 若线程过程函数所返回的指针指向动态分配的内存,
则还需保证在用过该内存之后释放之。
获取线程自身的 ID
=========
pthread_t pthread_self (void);
成功返回调用线程的 ID,不会失败。
比较两个线程的 ID
=========
int pthread_equal (pthread_t t1, pthread_t t2);
若参数 t1 和 t2 所标识的线程 ID 相等,则返回非零,否则返回 0。
某些实现的 pthread_t 不是 unsigned long int 类型,
可能是结构体类型,无法通过“==”判断其相等性。
范例:equal.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_t g_main;
void* ismain (void* arg) {
// if (pthread_self () == g_main)
if (pthread_equal (pthread_self (), g_main))
printf ("我是主线程!\n");
else
printf ("我不是主线程!\n");
return NULL;
}
int main (void) {
g_main = pthread_self ()
ismain (NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, ismain, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
return 0;
}
终止线程
====
1) 从线程过程函数中 return。
2) 调用 pthread_exit 函数。
void pthread_exit (void* retval);
retval - 和线程过程函数的返回值语义相同。
注意:在任何线程中调用 exit 函数都将终止整个进程。
范例:exit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
double* s = malloc (sizeof (double));
// exit (0);
*s = PAI * r * r;
pthread_exit (s); // <==> return s;
*s = 2 * PAI * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
线程执行轨迹
======
1) 同步方式 (非分离状态):
创建线程之后调用 pthread_join 函数等待其终止,并释放线程资源。
2) 异步方式 (分离状态):
无需创建者等待,线程终止后自行释放资源。
int pthread_detach (pthread_t thread);
使 thread 参数所标识的线程进入分离 (DETACHED) 状态。
处于分离状态的线程终止后自动释放线程资源,且不能被 pthread_join 函数等待。
成功返回 0,失败返回错误码。
范例:detach.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
int i;
for (i = 0; i < 200; i++) {
putchar ('-');
usleep (50000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
// pthread_detach () 写在 thread_proc () 里面依然会被 pthread_join () 捕获,无效果;
if ((error = pthread_detach (tid)) != 0) {
fprintf (stderr, "pthread_detach: %s\n", strerror (error));
return -1;
}
/*
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
*/
int i;
for (i = 0; i < 200; i++) {
putchar ('+');
usleep (100000);
}
printf ("\n");
return 0;
}
取消线程
====
1) 向指定线程发送取消请求
int pthread_cancel (pthread_t thread);
成功返回 0,失败返回错误码。
注意:该函数只是向线程发出取消请求,并不等待线程终止。
缺省情况下,线程在收到取消请求以后,并不会立即终止,而是仍继续运行,直到其达到某个取消点。
在取消点处,线程检查其自身是否已被取消了,并做出相应动作。
当线程调用一些特定函数时,取消点会出现。
2) 设置调用线程的可取消状态
int pthread_setcancelstate (int state, int* oldstate);
成功返回 0,并通过 oldstate 参数输出原可取消状态
(若非 NULL),失败返回错误码。
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消请求 (缺省)。
PTHREAD_CANCEL_DISABLE - 忽略取消请求。
3) 设置调用线程的可取消类型
int pthread_setcanceltype (int type, int* oldtype);
成功返回 0,并通过 oldtype 参数输出原可取消类型
(若非 NULL),失败返回错误码。
type取值:
PTHREAD_CANCEL_DEFERRED - 延迟取消(缺省)。
被取消线程在接收到取消请求之后并不立即响应,
而是一直等到执行了特定的函数(取消点)之后再响应该请求。
PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消。
被取消线程可以在任意时间取消,不是非得遇到取消点才能被取消。
但是操作系统并不能保证这一点。
范例:cancel.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void elapse (void) {
size_t i;
for (i = 0; i < 800000000; ++i);
}
void* thread_proc (void* arg) {
/*
int error = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
if (error) {
fprintf (stderr, "pthread_setcancelstate: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*//*
int error = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (error) {
fprintf (stderr, "pthread_setcanceltype: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*/
for (;;) {
printf ("线程:子在川上曰,逝者如斯夫。\n");
elapse ();
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
printf ("按<回车>取消线程...\n");
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
getchar ();
if ((error = pthread_cancel (tid)) != 0) {
fprintf (stderr, "pthread_cancel: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
printf ("已发送取消请求,等待线程终止...\n");
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("线程已终止。\n");
return 0;
}
线程属性
====
创建线程函数
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* restrict attr,
void* (*start_routine) (void*), void* restrict arg);
第二个参数即为线程属性,传空指针表示使用缺省属性。
typedef struct {
/* 分离状态 :
PTHREAD_CREATE_DETACHED - 分离线程。
PTHREAD_CREATE_JOINABLE(缺省) - 可汇合线程。
*/
int detachstate;
/* 竞争范围 :
PTHREAD_SCOPE_SYSTEM - 在系统范围内竞争资源。
PTHREAD_SCOPE_PROCESS(Linux不支持) - 在进程范围内竞争资源。
*/
int scope;
/* 继承特性 :
PTHREAD_INHERIT_SCHED(缺省) - 调度属性自创建者线程继承。
PTHREAD_EXPLICIT_SCHED - 调度属性由后面两个成员确定。
*/
int inheritsched;
/* 调度策略 :
SCHED_FIFO - 先进先出策略。
没有时间片; 一个 FIFO 线程会持续运行,直到阻塞或有高优先级线程就绪。
当 FIFO 线程阻塞时,系统将其移出就绪队列,待其恢复时再加到同优先级就绪队列的末尾。
当 FIFO 线程被高优先级线程抢占时,它在就绪队列中的位置不变。
因此一旦高优先级线程终止或阻塞,被抢占的 FIFO 线程将会立即继续运行。
SCHED_RR - 轮转策略。
给每个 RR 线程分配一个时间片,一但 RR 线程的时间片耗尽,系统即将移到就绪队列的末尾。
SCHED_OTHER(缺省) - 普通策略。
静态优先级为 0。任何就绪的 FIFO 线程或 RR 线程,都会抢占此类线程。
*/
int schedpolicy;
/* 调度参数 :
struct sched_param {
int sched_priority; // 静态优先级
};
*/
struct sched_param schedparam;
// 栈尾警戒区大小 (字节),缺省一页 (4096字节)。
size_t guardsize;
// 栈地址
void* stackaddr;
// 栈大小 (字节)
size_t stacksize;
} pthread_attr_t;
不要手工读写该结构体,
而应调用 pthread_attr_set/get 函数设置/获取具体属性项。
1) 设置线程属性
第一步,初始化线程属性结构体
int pthread_attr_init (pthread_attr_t* attr);
第二步,设置具体线程属性项
int pthread_attr_setdetachstate (pthread_attr_t* attr, int detachstate);
int pthread_attr_setscope (pthread_attr_t* attr, int scope);
int pthread_attr_setinheritsched (pthread_attr_t* attr, int inheritsched);
int pthread_attr_setschedpolicy (pthread_attr_t* attr, int policy);
int pthread_attr_setschedparam (pthread_attr_t* attr, const struct sched_param* param);
int pthread_attr_setguardsize (pthread_attr_t* attr, size_t guardsize);
int pthread_attr_setstackaddr (pthread_attr_t* attr, void* stackaddr);
int pthread_attr_setstacksize (pthread_attr_t* attr, size_t stacksize);
int pthread_attr_setstack (pthread_attr_t* attr, void* stackaddr, size_t stacksize);
第三步,以设置好的线程属性结构体为参数创建线程
int pthread_create (pthread_t* restrict thread,
const pthread_attr_t* testrict attr,
void* (*start_routine) (void*), void* restrict arg);
第四步,销毁线程属性结构体
int pthread_attr_destroy (pthread_attr_t* attr);
2) 获取线程属性
第一步,获取线程属性结构体
int pthread_getattr_np (pthread_t thread, pthread_attr_t* attr);
第二步,获取具体线程属性项
int pthread_attr_getdetachstate (pthread_attr_t* attr, int* detachstate);
int pthread_attr_getscope (pthread_attr_t* attr, int* scope);
int pthread_attr_getinheritsched (pthread_attr_t* attr, int* inheritsched);
int pthread_attr_getschedpolicy (pthread_attr_t* attr, int* policy);
int pthread_attr_getschedparam (pthread_attr_t* attr, struct sched_param* param);
int pthread_attr_getguardsize (pthread_attr_t* attr, size_t* guardsize);
int pthread_attr_getstackaddr (pthread_attr_t* attr, void** stackaddr);
int pthread_attr_getstacksize (pthread_attr_t* attr, size_t* stacksize);
int pthread_attr_getstack (pthread_attr_t* attr, void** stackaddr, size_t* stacksize);
以上所有函数成功返回 0,失败返回错误码。
范例:attr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
int printattrs (pthread_attr_t* attr) {
printf("------- 线程属性 -------\n");
int detachstate;
int error = pthread_attr_getdetachstate (attr, &detachstate);
if (error) {
fprintf (stderr, "pthread_attr_getdetachstate: %s\n", strerror (error));
return -1;
}
printf("分离状态: %s\n",
(detachstate == PTHREAD_CREATE_DETACHED) ? "分离线程" :
(detachstate == PTHREAD_CREATE_JOINABLE) ? "可汇合线程" : "未知");
int scope;
if ((error = pthread_attr_getscope (attr, &scope)) != 0) {
fprintf (stderr, "pthread_attr_getscope: %s\n", strerror (error));
return -1;
}
printf ("竞争范围: %s\n",
(scope == PTHREAD_SCOPE_SYSTEM) ? "系统级竞争" :
(scope == PTHREAD_SCOPE_PROCESS) ? "进程级竞争" : "未知");
int inheritsched;
if ((error = pthread_attr_getinheritsched (attr, &inheritsched)) != 0) {
fprintf (stderr, "pthread_attr_getinheritsched: %s\n", strerror (error));
return -1;
}
printf ("继承特性: %s\n",
(inheritsched == PTHREAD_INHERIT_SCHED) ? "继承调用属性" :
(inheritsched == PTHREAD_EXPLICIT_SCHED) ? "显式调用属性" : "未知");
int schedpolicy;
if ((error = pthread_attr_getschedpolicy(attr, &schedpolicy)) != 0) {
fprintf (stderr, "pthread_attr_getschedpolicy: %s\n", strerror (error));
return -1;
}
printf ("调度策略: %s\n",
(schedpolicy == SCHED_OTHER) ? "普通" :
(schedpolicy == SCHED_FIFO) ? "先进先出" :
(schedpolicy == SCHED_RR) ? "轮转" : "未知");
struct sched_param schedparam;
if ((error = pthread_attr_getschedparam (attr, &schedparam)) != 0) {
fprintf (stderr, "pthread_attr_getschedparam: %s\n", strerror (error));
return -1;
}
printf ("调度优先级:%d\n", schedparam.sched_priority);
size_t guardsize;
if ((error = pthread_attr_getguardsize(attr, &guardsize)) != 0) {
fprintf (stderr, "pthread_attr_getguardsize: %s\n", strerror (error));
return -1;
}
printf ("栈尾警戒区:%u字节\n", guardsize);
/*
void* stackaddr;
if ((error = pthread_attr_getstackaddr (attr, &stackaddr)) != 0) {
fprintf (stderr, "pthread_attr_getstackaddr: %s\n", strerror (error));
return -1;
}
printf ("栈地址: %p\n", stackaddr);
size_t stacksize;
if ((error = pthread_attr_getstacksize (attr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstacksize: %s\n", strerror (error));
return -1;
}
printf ("栈大小: %u字节\n", stacksize);
*/
void* stackaddr;
size_t stacksize;
if ((error = pthread_attr_getstack (attr, &stackaddr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstack: %s\n", strerror (error));
return -1;
}
printf ("栈地址: %p\n", stackaddr);
printf ("栈大小: %u字节\n", stacksize);
printf("------------------------\n");
return 0;
}
void* thread_proc (void* arg) {
pthread_attr_t attr;
int error = pthread_getattr_np (pthread_self (), &attr);
if (error) {
fprintf (stderr, "pthread_getattr_np: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
if (printattrs (&attr) < 0)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
return NULL;
}
int main (int argc, char* argv[]) {
int error;
pthread_attr_t attr, *pattr = NULL;
if (argc > 1) {
if (strcmp (argv[1], "-s")) {
fprintf (stderr, "用法:%s [-s]\n", argv[0]);
return -1;
}
if ((error = pthread_attr_init (&attr)) != 0) {
fprintf (stderr, "pthread_attr_init: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setdetachstate (&attr,
PTHREAD_CREATE_DETACHED)) != 0) {
fprintf (stderr, "pthread_attr_setdetachstate: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setinheritsched (&attr,
PTHREAD_EXPLICIT_SCHED)) != 0) {
fprintf (stderr, "pthread_attr_setinheritsched: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setstacksize (&attr, 4096*10)) != 0) {
fprintf (stderr, "pthread_attr_setstack: %s\n", strerror (error));
return -1;
}
pattr = &attr;
}
pthread_t tid;
if ((error = pthread_create (&tid, pattr, thread_proc, NULL)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if (pattr)
if ((error = pthread_attr_destroy (pattr)) != 0) {
fprintf (stderr, "pthread_attr_destroy: %s\n", strerror (error));
return -1;
}
pause ();
return 0;
}