Linux 系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库 libpthread.a。
1. 线程的创建和使用
线程的创建是用下面的几个函数来实现的.
int
pthread_create(pthread_t
*
thread,pthread_attr_t
*
attr,
void
*
(
*
start_routine)(
void
*
),
void
*
arg);
void
pthread_exit(
void
*
retval);
int
pthread_join(pthread
*
thread,
void
**
thread_return);
pthread_create创建一个线程,thread是用来表明创建线程的ID,attr指出线程创建时候的属性,我们用NULL来表明使用缺省属性.start_routine函数指针是线程创建成功后开始执行的函数,arg是这个函数的唯一一个参数.表明传递给start_routine 的参数.
pthread_exit函数和exit函数类似用来退出线程.这个函数结束线程,释放函数的资源,并在最后阻塞,直到其他线程使用
pthread_join函数等待它.然后将*retval的值传递给**thread_return.由于这个函数释放所以的函数资源,所以 retval不能够指向函数的局部变量.
pthread_join和wait调用一样用来等待指定的线程.
下面展示一个最简单的多线程程序。
#include
<
stdio.h
>
#include
<
pthread.h
>
void
thread(
void
)
{
int
i;
for
(i
=
0
;i
<
3
;i
++
)
printf(
"
This is a pthread.\n
"
);
}
int
main(
void
)
{
pthread_t id;
int
i,ret;
ret
=
pthread_create(
&
id,NULL,(
void
*
) thread,NULL);
if
(ret
!=
0
)
{
printf (
"
Create pthread error!\n
"
);
exit (
1
);
}
for
(i
=
0
;i
<
3
;i
++
)
printf(
"
This is the main process.\n
"
);
pthread_join(id,NULL);
return
(
0
);
}
2. 修改线程的属性
上面用pthread_create函数创建了一个线程,在这个线程中,我们使用了默认参数,即将该函数的第二个参数设为NULL。属性结构为pthread_attr_t,它同样在头文件/usr/include/pthread.h中定义。属性值不能直接设置,须使用相关函数进行操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。
关于线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process)。轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的"绑"在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。
设置线程绑定状态的函数为pthread_attr_setscope,它有两个参数,第一个是指向属性结构的指针,第二个是绑定类型,它有两个取值:PTHREAD_SCOPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)。下面的代码即创建了一个绑定的线程。
#include
<
pthread.h
>
pthread_attr_t attr;
pthread_t tid;
/*
初始化属性值,均设为默认值
*/
pthread_attr_init(
&
attr);
pthread_attr_setscope(
&
attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(
&
tid,
&
attr, (
void
*
) my_function, NULL);
线程的分离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。设置线程分离状态的函数为 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD_CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在 pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用 pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数 pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。下面即是一段简单的例子。
#include
<
pthread.h
>
#include
<
sched.h
>
pthread_attr_t attr;
pthread_t tid;
sched_param param;
int
newprio
=
20
;
pthread_attr_init(
&
attr);
pthread_attr_getschedparam(
&
attr,
&
param);
param.sched_priority
=
newprio;
pthread_attr_setschedparam(
&
attr,
&
param);
pthread_create(
&
tid,
&
attr, (
void
*
)myfunction, myarg);
[参考]
http://fanqiang.chinaunix.net/a4/b2/20010508/113838.html
http://fanqiang.chinaunix.net/a4/b8/20010811/0905001105.html