当前位置: 首页 > 工具软件 > pthreads > 使用案例 >

Pthreads线程的基本常识

仇飞鹏
2023-12-01

1.Pthreads中线程的接口函数

与线程相关的头文件为pthread.h,编译时要连接的库为pthread

pthread_t thread;

线程的数据类型为pthread_t

int pthread_equal(pthread t1,pthread t2);

判断两个线程标识符是不是代表的是同一个线程。线程标识符只有相等和不等的关系,没有大小关系。

int pthread_create(pthread_t * thread,

               const pthread_attr_t * attr, void *(*start)(void *),void * arg);

pthread_create函数将创建一个线程,第一个传出参数为系统分配给线程的标识符。第二个参数为线程设置的属性。第三个参数为线程开始运行后执行的启动函数。第四个参数为函数要用到的参数。

pthread_t pthread_self(void);

pthread_self函数将获得当前线程的标识符。返回值即为当前线程的标识符。获得线程标识符的方法有两种:(1)使用pthread_create函数.2)使用pthread_self函数.

int sched_yield(void);

志愿让出处理器的使用权给其他线程使用。

int pthread_exit(void * value_ptr);

当前线程退出。

int pthread_detach(pthread_t thread);

当线程进入终止状态时,清理线程所占资源后进入回收状态。

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

阻塞等待thread线程执行结束,并得到该线程的返回值。注意第二个参数应该为指针的指针。该函数内部会负责调用pthread_detach保证线程的资源得到释放。

 

2.主线程和普通线程的区别

1)主线程使用returnexit、或者正常执行到主函数的结尾退出时,所有的线程都将退出。如果主线程需要其他线程执行结束后才退出,可以使用以下方式:1)调用pthread_join,这时调用的主线程将被阻塞,直到join的线程执行结束后,才接着往下执行。2)调用pthread_exit函数,但是pthread_exit函数返回主线程后,系统不能正常得到程序的返回状态。3)使用条件变量等待其他线程执行结束。

2)主线程的参数传递方式和普通线程不一样,主线程通过main函数中的argcargv得到各个参数,而普通线程需要将所有的参数封装到一起,传给线程的参数。

3)一般主线程的栈的大小比普通现成的大很多。主线程使用的是进程的栈,所以会比较大。

4)主线程的main函数是被外部的某个函数调用的,一般是链接的crt0.o这个文件。ctr0C running time)是一个启动例程,负责完成进程的初始化工作后,调用main函数。普通线程直接调用start函数。

 

3.线程的资源回收

         线程执行完毕之后应该是放其所占用的资源:包括虚拟内存,堆栈,锁,信号量等信息。一般线程调用了pthread_cancelpthread_exit或者执行完其start函数中的逻辑或者执行完了return语句,线程的状态将进入终止状态。进入终止状态的线程并没有释放它所占用的资源,一般有以下三种方式:

         1)创建线程的时候在第二个参数中设置detach属性。

         2)使用pthread_detach函数

         3)使用pthread_join函数

         线程所占用的资源有些被释放,有些被回收利用。在启动新的线程的时候可以减少一部分开销。

         线程的分离(detach)同线程执行其逻辑没有必然联系。还有需要注意的是,一个线程只能被join一次,如果有多个线程都需要等待一个线程,使用信号量实现。

         pthread_cancel结束的线程,其返回值只有一种:PTHREAD_CANCELLED

 

4.线程的返回值

         使用线程的返回值最容易出现的错误就是使用了线程内部的栈中数据的地址作为返回值。A线程创建了B线程,B线程可能会在A线程开始执行join之前,已经detach掉了。其栈早已失效,这时如果线程内部返回的是栈中某数据的地址一定出错。

         一般线程的返回值可以使用以下三种方式:

         1)使用全局变量

         2)线程内部使用malloc开辟空间,回传给需要的线程。该线程负责释放这段内存

         3)使用传出参数,即调用线程使用malloc在堆上开辟空间,并负责数据的维护

 

5.代码示例

 

 
 
  1. #include<stdio.h> 
  2.  
  3. #include<pthread.h> 
  4.  
  5. #include "../error.h" 
  6.  
  7.   
  8.  
  9. void * thread_routin(void * arg) 
  10.  
  11.  
  12.         return arg; 
  13.  
  14.  
  15.   
  16.  
  17. int main(int argc,char * argv[]) 
  18.  
  19.  
  20.         pthread_t thread
  21.  
  22.         void * thread_result; 
  23.  
  24.         int status; 
  25.  
  26.         status = pthread_create(&thread,NULL,thread_routin,NULL); 
  27.  
  28.         if(0 != status) 
  29.  
  30.                 err_abort("create thread error.",status); 
  31.  
  32.         status = pthread_join(thread,&thread_result); 
  33.  
  34.         if(0 != status) 
  35.  
  36.                 err_abort("join thread error.",status); 
  37.  
  38.         if(NULL != thread_result) 
  39.  
  40.                 fprintf(stderr,"%s","Return value error.\n"); 
  41.  
  42.         return 0; 
  43.  
  44.  
  45. 以上程序是一个简单的参数传入传出的示例程序。 
  46.  
  47. #include<pthread.h> 
  48.  
  49. #include<stdio.h> 
  50.  
  51. #include<stdlib.h> 
  52.  
  53.   
  54.  
  55. int main(int argc,char * argv[]) 
  56.  
  57.  
  58.         pthread_t thread
  59.  
  60.         int status; 
  61.  
  62.         status = pthread_join(thread,NULL); 
  63.  
  64.         if(0 != status) 
  65.  
  66.         { 
  67.  
  68.                 fprintf(stderr,"%s \"%s\":%d: %s\n","thread join error",__FILE__,__LINE__,strerror(status)); 
  69.  
  70.                 abort(); 
  71.  
  72.         } 
  73.  
  74.         return 0; 
  75.  

以上程序是一个故意出错的程序,在Linux中程序会直接崩溃,提示“段错误”。

 

 
 
  1. #include<stdio.h> 
  2.  
  3. #include<pthread.h> 
  4.  
  5. #include<time.h> 
  6.  
  7.   
  8.  
  9. #include "../error.h" 
  10.  
  11. void * thread_routin(void *arg) 
  12.  
  13.  
  14.         sleep(5); 
  15.  
  16.         return arg; 
  17.  
  18.  
  19.   
  20.  
  21. int main(int argc,char *argv[]) 
  22.  
  23.  
  24.         pthread_t thread ; 
  25.  
  26.         int status; 
  27.  
  28.         int result; 
  29.  
  30.         status = pthread_create(&thread,NULL,thread_routin,NULL); 
  31.  
  32.         if(0 != status) 
  33.  
  34.                 err_abort("creating thread error.",status); 
  35.  
  36.         result = 1; 
  37.  
  38.         pthread_exit((void *)&result); 
  39.  
  40.         //return 0; 
  41.  

这是一个测试main线程调用pthread_exit能否返回需要的值的测试程序。该程序表明:在main线程中使用pthread_exit虽然能保证其他线程执行完毕,但是在系统无法得知整个程序的最后执行状态。

 
 
  1. #include<stdio.h> 
  2.  
  3. #include<pthread.h> 
  4.  
  5. #include<time.h> 
  6.  
  7.   
  8.  
  9. #include "../error.h" 
  10.  
  11. void * thread_routin(void *arg) 
  12.  
  13.  
  14.         //pthread_exit(arg); 
  15.  
  16.         return arg; 
  17.  
  18.  
  19.   
  20.  
  21. int main(int argc,char *argv[]) 
  22.  
  23.  
  24.         pthread_t thread ; 
  25.  
  26.         void * result; 
  27.  
  28.         int status; 
  29.  
  30.         int set_result = -1; 
  31.  
  32.         status = pthread_create(&thread,NULL,thread_routin,(void *)&set_result); 
  33.  
  34.         if(0 != status) 
  35.  
  36.                 err_abort("creating thread error.",status); 
  37.  
  38.         status = pthread_join(thread,&result); 
  39.  
  40.         if(0 != status) 
  41.  
  42.                 err_abort("joining thread error.",status); 
  43.  
  44.         printf("exit value is %d\n",*((int *)result)); 
  45.  
  46.         pthread_exit((void*)&set_result); 
  47.  

该程序对普通线程和主线程分别调用pthread_exit以测试线程的返回值。主线程的返回值系统无法得到,普通线程的返回值却可以得到。



本文转自hipercomer 51CTO博客,原文链接:http://blog.51cto.com/hipercomer/909941

 类似资料: