POSIX多线程——基本线程管理函数介绍

时间:2024-04-10 12:37:04
POSIX基本的几个线程管理函数见下表:
------------------------------------------------------------------------------------------
                     POSIX函数                                                         描述
-------------------------------------------------------------------------------------------
                    pthread_create                                   创建一个线程
                    pthread_self                                       找出自己的线程ID
                    pthread_equal                                    测试2个线程ID是否相等
                    pthread_detach                                  设置线程以释放资源
                    pthread_join                                        等待一个线程
                    pthread_cancel                                   终止另一个线程
                    pthread_exit                                        退出线程,而不退出进程
                    pthread_kill                                         向线程发送一个信号
-------------------------------------------------------------------------------------------
(1)线程ID、获取和比较
POSIX线程由一个pthread_t类型的ID来引用。线程可以通过调用pthread_self ()函数获得自己的线程ID,这里没有对pthread_self 定义错误。
==========================
概要:
#include <pthread.h>                     
pthread_t   pthread_self (void);   
==========================
由于pthread_t  可能是一个结构,所以不能由==来直接进行比较。这里可以使用函数pthread_equal()来比较线程ID是否相等,这里没有对pthread_equal定错误,如果两个线程ID相等,返回非0值,否则返回0.
============================================
概要:
#include <pthread.h>                     
int   pthread_equal(pthread_t  t1, pthread_t  t2 );   
============================================
(2)创建线程
可以使用pthread_create()创建一个线程。POSIX的pthread_create()创建的线程是可以直接运行的,而不需要一个单独的启动操作。
==========================================
概要:
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
                   const pthread_attr_t *restrict attr,
                   void *(*start_routine)(void *), 
                   void *restrict arg);
==========================================
在上述函数中,thread指向新创建的线程ID;参数attr表示一个封装了线程各种属性的属性对象(比如栈大小、调度等信息,后面会专门介绍),如果attr为NULL,则使用默认属性进行创建;第三个参数start_routine是线程开始执行时调用的函数名字;第四个参数arg指针指向的数据是start_routine的参数。如果成功,函数返回0,否则返回非零错误码。
下面例子中的代码就是连续创建10个线程,线程中执行的代码仅为打印自己的线程ID,和所属进程ID:
#include <pthread.h>
#include <stdio.h> void *print_thread(int *i)
{
fprintf(stderr,"number:%d,pid:%d,tid:%lld.\n",*i,getpid(),(long long)pthread_self());
return NULL;
} int main(int argc, char* argv[ ] )
{
pthread_t tids[];
int i;
for(i=;i<;i++)
{
if(pthread_create(&tids[i],NULL,print_thread,&i)==-)
{
fprintf(stderr,"\nERROR: fail to creat thread.");
tids[i]= pthread_self();
}
}
return ;
}
执行结果:
gaolu@gaolu-desktop:~$ ./thr
number:0,pid:5579,tid:3085089680.
number:1,pid:5579,tid:3076696976.
number:2,pid:5579,tid:3068304272.
number:3,pid:5579,tid:3059911568.
number:4,pid:5579,tid:3051518864.
number:5,pid:5579,tid:3043126160.
number:6,pid:5579,tid:3034733456.
number:7,pid:5579,tid:3026340752.
number:8,pid:5579,tid:3017948048.
number:9,pid:5579,tid:3009555344.
gaolu@gaolu-desktop:~$
(3)线程的分离(detach)和连接(join)
一般情况下,线程在退出时,是不会释放它的资源的;
如果将线程分离,即创建线程以后调用pthread_detach(tid)或者线程自身调用pthread_detach(pthread_self())都可以,它设置线程的内部选项来说明,线程退出以后存储空间可以被重新收回,分离线程退出时不会报告他们的状态。
如果线程没有分离,那么它是可以接合(join)的,pthread_join和进程级别的函数wait_pid非常类似,该函数将调用线程挂起,直到第一个参数指定的目标线程终止为止。如果创建线程对子线程调用了pthread_join(), 子线程退出以后,资源在进程退出以后被回收。参数value_ptr为指向返回值的指针,这个返回值是目标线程return 或者传递给pthread_exit()的。
为了防止内存泄漏,长时间运行的线程最终应该为每个线程调用pthread_join() 或者pthread_detach()。
===========================================
概要:
#include <pthread.h>
int pthread_join(pthread_t th, void **value_ptr )
int pthread_detach(pthread_t thread )
===========================================
下面一个示例程序演示了pthread_detach和pthread_join之间的关系。
(1)子线程将自己detach了,这种情况下线程是不能被join的。
#include <pthread.h>
#include <stdio.h>
void *print_thread(void *ptr)
{
if(pthread_detach(pthread_self())==)
{
fprintf(stderr,"tid:%lld,I have detached myself successfully.\n",(long long)pthread_self( ) );
}
else
{
fprintf(stderr,"\nERROR:detach failed.");
}
return NULL;
}
int main(int argc, char* argv[])
{
pthread_t tid;
int *exitcode;
if(pthread_create(&tid,NULL,print_thread,NULL)==-)
{
fprintf(stderr,"\nERROR: fail to creat thread.");
}
fprintf(stderr,"my pid is %d.\n",getpid());
if(pthread_join(tid,&exitcode)!=)
{
fprintf(stderr,"ERROR: fail to join thread.\n");
}
else
{
fprintf(stderr,"parent end successfully.\n");
} return ;
}
gaolu@gaolu-desktop:~$ ./thr
tid:3084360592,I have detached myself successfully.
my pid is 5652.
ERROR: fail to join thread.
gaolu@gaolu-desktop:~$
(2)修改创建的线程只是做了普通的打印信息,join可以执行成功。
void *print_thread(void *ptr)
{
     fprintf(stderr,"My tid:%lld.\n",(long long)pthread_self());
}
gaolu@gaolu-desktop:~$ ./thr
My tid:3085216656.
my pid is 5702.
parent end successfully.
gaolu@gaolu-desktop:~$ 
(4)线程退出和取消
线程return一个指针value_ptr的相当于隐式地调用了pthread_exit(value_ptr)函数。如果进程的最后一个线程调用了pthread_exit,进程就会带着状态返回值0退出。
对于一个被join了的线程来说,其返回值vlaue_ptr是可用的。也就是说value_ptr一定是要指向线程结束以后还存在的数据------这个问题可以通过几种方式解决:比如创建线程给被创建的线程传递参数时,参数中传递一个指针,作为被创建线程的返回值,这样返回值是位于创建线程的栈上;另外在被创建线程malloc内存,将指针作为返回值使用也可以。
另外,线程可以通过取消机制迫使其他线程返回。线程通过执行pthread_cancel()来请求取消另一个线程,该函数在发出取消请求以后就返回了,而不需要阻塞;而实际结果由目标线程的类型和取消状态决定(状态可以通过函数设置的)。
==================================================
概要:
#include <pthread.h>
int pthread_exit(void *value_ptr );
int pthread_cancel( pthread_t thread );
int pthread_setcancelstate (int state, int *oldstate);
==================================================
如果线程收到cancel的请求时,处于PTHREAD_CANCEL_ENABLE,它就接受取消请求;否则如果处于PTHREAD_CANCEL_DISABLE的状态,取消请求就会被保持在挂起状态。默认情况下,线程处于PTHREAD_CANCEL_ENABLE状态。

本文出自 “淡泊明志,宁静致远” 博客,请务必保留此出处http://keren.blog.51cto.com/720558/176759