Unix C, Day09

================
第九课  线程管理
================

一、基本概念
------------

1. 线程就是程序的执行路线,即进程内部的控制序列,
   或者说是进程的子任务。

2. 线程,轻量级,不拥有自己独立的内存资源,
   共享进程的代码区、数据区、堆区(注意没有栈区, 线程拥有自己独立的栈)、
   环境变量和命令行参数、文件描述符、信号处理函数、
   当前目录、用户ID和组ID等资源。

3. 线程拥有自己独立的栈,因此也有自己独立的局部变量。

4. 一个进程可以同时拥有多个线程,
   即同时被系统调度的多条执行路线,
   但至少要有一个主线程。

二、基本特点
------------

1. 线程是进程的一个实体, 可作为系统独立调度和分派的基本单位。 
    (p.s.  进程是一堆数据资源,没有所谓调度,调度是针对动作的,对于动作是否要进行我们需要调度)

2.  线程有不同的状态,系统提供了多种线程控制原语(所谓原语就是进行多线程控制的函数), 如创建线程、销毁线程等等。

3.  线程不拥有自己的资源(线程所独立拥有的栈只是为了执行动作需要的临时场地,不算资源, 因为临时场地不可持续), 
    只拥有从属于进程的全部资源, 所有的资源分配都是面向进程的。

4. 一个进程中可以有多个线程并发地运行。
   它们可以执行相同的代码,也可以执行不同的代码。

5. 同一个进程的多个线程都在同一个地址空间内活动,
   因此相对于进程,线程的系统开销小,任务切换快。

6. 线程间的数据交换不需要依赖于类似IPC的特殊通信机制, 简单而高效。

7. 每个线程拥有自己独立的线程ID、寄存器信息、函数栈、
   错误码和信号掩码。

8. 线程之间存在优先级的差异。

三、POSIX线程(pthread)
----------------------

1. 早期厂商各自提供私有的线程库版本,
   接口和实现的差异非常大,不易于移植。

2. IEEE POSIX 1003.1c (1995)标准,
   定义了统一的线程编程接口,
   遵循该标准的线程实现被统称为POSIX线程,即pthread。

3. pthread包含一个头文件pthread.h,
   和一个接口库libpthread.so。

#include <pthread.h>

...

gcc ... -lpthread

4. 功能

1) 线程管理:创建/销毁线程、分离/联合线程、
   设置/查询线程属性。

2) 线程同步

A. 互斥量:创建/销毁互斥量、加锁/解锁互斥量、
   设置/查询互斥量属性。

B. 条件变量:创建/销毁条件变量、等待/触发条件变量、
   设置/查询条件变量属性。

四、线程函数
------------

1. 创建线程
~~~~~~~~~~~

int pthread_create (pthread_t* restrict thread, //thread        - 线程ID,输出参数。
                                //pthread_t在某些厂商的实现上即unsigned long int。

    const pthread_attr_t* restrict attr,        //attr          - 线程属性,NULL表示缺省属性。
                                                //pthread_attr_t可能是整型也可能是结构,
                                                //因实现而异。

    void* (*start_routine) (void*),             //start_routine - 线程过程函数指针,
                                                //参数和返回值的类型都是void*。
                                                //启动线程本质上就是调用一个函数,
                                                //只不过是在一个独立的线程中调用的,
                                                //函数返回即线程结束。

    void* restrict arg                          //arg           - 传递给线程过程函数的参数。
                                                //线程过程函数的调用者是系统内核,
                                                //而非用户代码,
                                                //因此需要在创建线程时指定参数。
    );

成功返回0,失败返回错误码。

注意:

1) restrict: C99引入的编译优化指示符,
   提高重复解引用同一个指针的效率。

2) 在pthread.h头文件中声明的函数,
   通常以直接返回错误码的方式表示失败,
   而非以错误码设置errno并返回-1来指示成功与失败。

3) main函数即主线程,
   程序一运行内核就会启动一个线程,这个线程的开始就执行main函数,这个线程称为主线程,main函数返回即主线程结束,
   主线程结束即进程结束, 进程一但结束其所有的线程即结束。

4) 应设法保证在线程过程函数执行期间,
   其参数所指向的目标持久有效。

创建线程。范例:create.c
/*
 * 文件名: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) {
        setbuf(stdout, NULL);
	pthread_t tid;
	int error = pthread_create (&tid, NULL, thread_proc,
		"我是快乐的子线程!");
	if (error) {
		fprintf (stderr, "pthread_create: %s\n", strerror (error));
		return -1;
	}

	printf ("%lu线程:我是主线程,创建了%lu线程。\n", pthread_self (),
		tid);

	sleep (1);

	return 0;
}



线程并发。范例:concur.c
/*
 * 文件名: 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 ("%*c\n", ((size_t)arg + 1) * 1, 'A' + (i + 1) % 10);
		usleep (50000);
	}

	return NULL;
}

int main (void) {
	pthread_t tids[50];

	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
/*
 * 文件名: 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) {
		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;
}



2. 等待线程
~~~~~~~~~~~

int pthread_join (pthread_t thread, void** retval);

等待thread参数所标识的线程结束,
成功返回0,失败返回错误码。

范例:ret.c
/*
 * 文件名: 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) 若线程过程函数所返回的指针指向动态分配的内存,
   则还需保证在用过该内存之后释放之。

3. 获取线程自身的ID
~~~~~~~~~~~~~~~~~~~

pthread_t pthread_self (void);

成功返回调用线程的ID,不会失败。

4. 比较两个线程的ID
~~~~~~~~~~~~~~~~~~~

int pthread_equal (pthread_t t1, pthread_t t2);

若参数t1和t2所标识的线程ID相等,则返回非零,否则返回0。

某些实现的pthread_t不是unsigned long int类型,
可能是结构体类型,无法通过“==”判断其相等性。

范例:equal.c
/*
 * pthread_equal()函数练习
 * */
#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 ();


	pthread_t tid;
	int error = pthread_create (&tid, NULL, ismain, NULL);
	if (error) {
		fprintf (stderr, "pthread_create: %s\n", strerror (error));
		return -1;
	}

	ismain (NULL);

	if ((error = pthread_join (tid, NULL)) != 0) {
		fprintf (stderr, "pthread_join: %s\n", strerror (error));
		return -1;
	}

	return 0;
}



5. 终止线程
~~~~~~~~~~~

1) 从线程过程函数中return。

2) 调用pthread_exit函数。
void pthread_exit (void* retval);     //等价于return retval;
                                      //也就是说pthread_exit的参数retval - 和线程过程函数的返回值语义相同。

注意:在任何线程中调用exit函数都将终止整个进程。

范例:exit.c
/*文件名: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;
}



6. 线程执行轨迹
~~~~~~~~~~~~~~~

1) 同步方式(PTHREAD_CREATE_JOINABLE, 就是非分离状态,或称为可汇合态, 或称为可汇合线程):
   创建线程之后调用pthread_join函数等待其终止,
   并释放线程资源。

2) 异步方式(PTHREAD_CREATE_DETACHED, 就是分离状态, 或称为分离态, 或称为分离线程):
   无需创建者等待,线程终止后自行释放资源。

int pthread_detach (pthread_t thread);

使thread参数所标识的线程进入分离(DETACHED)状态。
处于分离状态的线程终止后自动释放线程资源,
且不能被pthread_join函数等待。

成功返回0,失败返回错误码。

范例:detach.c
/*
 *文件名: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;
	}

	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;
}



7. 取消线程
~~~~~~~~~~~

1) 向指定线程发送取消请求

int pthread_cancel (pthread_t thread);

成功返回0,失败返回错误码。

注意:该函数只是向线程发出取消请求, 该函数不阻塞,并不等待线程终止。
      缺省情况下,线程在收到取消请求以后,并不会立即终止,
      而是仍继续运行,直到其达到某个取消点。在取消点处,
      线程检查其自身是否已被取消了,并做出相应动作。(p.s.  当线程调用一些特定函数时,取消点会出现。)

2) 设置调用线程的可取消状态

int pthread_setcancelstate (int state,     //state取值:
                                           //PTHREAD_CANCEL_ENABLE  - 接受取消请求(缺省)。
                                           //PTHREAD_CANCEL_DISABLE - 忽略取消请求。
    int* oldstate                          //可通过oldstate参数(若非NULL)输出原可取消状态
    );

成功返回0,失败返回错误码。


3) 设置调用线程的可取消类型

int pthread_setcanceltype (int type,       //type取值:
                                           //PTHREAD_CANCEL_DEFERRED     - 延迟取消(缺省)。
                                           //被取消线程在接收到取消请求之后并不立即响应,
                                           //而是一直等到执行了特定的函数(取消点)之后再响应该请求。
                                           //
                                           //PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消。
                                           //被取消线程可以在任意时间取消,
                                           //不是非得遇到取消点才能被取消。
                                           //但是操作系统并不能保证这一点。

    int* oldtype                       //可通过oldtype参数(若非NULL)输出原可取消类型
    );

成功返回0,失败返回错误码。


范例:cancel.c
/*
 *文件名: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;
}



8. 线程属性
~~~~~~~~~~~

创建线程函数
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
/*
 *文件名: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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值