POSIX多线程程序设计学习篇之一(线程管理)

来源:互联网 发布:李氏筋骨散淘宝 编辑:程序博客网 时间:2024/05/21 09:54

首先来一份最简单的开胃篇代码来认识多线程

#include<pthread.h>#include<stdio.h>void *thread_routine(void *arg)//子线程执行的函数{     printf("son thread\n");     int i = 0;     for(i = 0; i<100; i++)          printf("i =%d\n",i);     return arg;}void main(int argc,char *argv[]){    int a = 0;    printf("a = %d\n",a);        pthread_t thread_id;    void *thread_result;    int status;        status = pthread_create(&thread_id,NULL,thread_routine,NULL);//创建子线程    if(status != 0)    printf("create thread error");    else         printf("create thread success%ld\n",(unsigned long)thread_id);          status = pthread_join(thread_id,&thread_result);//阻塞主线程,直到子线程执行完毕。}


一,Pthread API 命名约定如下:





二,线程的创建、退出等函数介绍

pthread_create(thread,attr,function,arg)//线程的创建(线程结构变量,属性,线程函数入口,线程函数参数)

pthread_exit(status)

pthread_attr_init(attr)

pthread_attr_destroy(attr)

一个进程可以创建的线程最大数量取决于系统实现

线程属性:  

  • 线程被创建时会带有默认的属性。其中的一些属性可以被程序员用线程属性对象来修改。 
  • pthread_attr_init 和 pthread_attr_destroy用于初始化/销毁先前属性对象。 
  • 其它的一些函数用于查询和设置线程属性对象的指定属性。 
  • 其他等等

结束终止:

     a, 线程从主线程(main函数的初始线程)返回。

     b, 线程调用了pthread_exit函数,显示的退出当前线程。

     c, 其它线程使用 pthread_cancel函数结束线程。

     d, 调用exec或者exit函数,整个进程结束。

如果main()在其他线程结束前用pthread_exit()退出了,其他线程将会继续执行。否则,他们会随着main的结束而终止。


三,链接和分离

1,在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。
joinable:能够被其他线程收回其资源和杀死;在被其他线程回收之前,系统资源是不释放的。
          当pthread_join()函数返回时,创建的线程才算终止。(系统默认)
detached:不能被其他线程回收或杀死的,系统资源在它终止时由系统自动释放。

线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的。

2,常用函数如下:

(1)线程的阻塞和分离

int pthread_join(pthread_t tid, void**thread_return); //阻塞本地线程,直到设置的线程tid执行结束。
int pthread_detach(pthread_t tid); //设置分离状态的方式
为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。

(2)设置和获得分类状态
pthread_attr_setdetachstate (attr,detachstate)
pthread_attr_getdetachstate (attr,detachstate)
其中detachstate参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)

(3)分离线程有个问题是,可能在pthread_create函数返回之前就终止了,就可能将线程ID和系统资源移交给其他的线程使用,
这样当前调用pthread_create的线程就得到了错误的线程号。(可以在被创建的线程里调用pthread_cond_timewait函数避免)

3,设置分离状态的方式
(1)调用 pthread_detach()函数
(2)创建线程时就将线程属性设置为detached 状态
   首先声明pthread_attr_t attr;
   然后初始化attr---pthread_attr_init(&attr);
   再然后设置线程类别---pthread_attr_setdetachstate(&attr,detachstatus);

   最后线程create完毕后释放attr--pthread_attr_destroy(&attr);

下面例子足以说明以上信息

#include <pthread.h> #include <stdio.h> #define NUM_THREADS  (3) #define JOIN_TO_DETACH (1)//三个宏只有一个能为1,测试三种情况#define ONLY_JOIN (0)#define ONLY_DETACH (0)void *fun(void *arg) {  #if JOIN_TO_DETACH   int status = pthread_detach(pthread_self());   printf("detach %d status= %x\n",((int*)arg)[0], (long)status); #endif   int i = 0;   for (i=0; i<5; i++)    {      printf("id = %d result = %d\n",((int*)arg)[0],i);      sched_yield();//将处理器交给另一个等待的程序   }    //pthread_exit(NULL); }  int main (int argc, char *argv[]) {    pthread_t thread[NUM_THREADS];    pthread_attr_t attr;   int a[NUM_THREADS][1];    int i;    int status = 0;   pthread_attr_init(&attr);#if JOIN_TO_DETACH || ONLY_JOIN   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); //设置成结合属性#else   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #endif   for(i=0; i<NUM_THREADS; i++)    {       a[i][0] = i;      printf("Creating thread %d\n", i);       pthread_create(&thread[i], &attr, fun, a[i]);    }       pthread_attr_destroy(&attr); #if ONLY_JOIN || DETACH_TO_JOIN   for(i=0; i<NUM_THREADS; i++)    {        status = pthread_join(thread[i],NULL);       printf("join %d status= %x\n",i, (long)status);    } #endif   pthread_exit(NULL);    return 0;} 



四,栈管理
pthread_attr_getstacksize (attr, stacksize)  
pthread_attr_setstacksize (attr, stacksize)  
pthread_attr_getstackaddr (attr, stackaddr)  
pthread_attr_setstackaddr (attr, stackaddr)
可以被程序用于将栈设置在指定的内存区域


五,补充

1,线程ID

pthread_self ()  //返回调用该函数的线程的唯一,系统分配的线程ID。
pthread_equal (thread1,thread2) // 比较两个线程ID,若不同返回0,否则返回非0值

 
注意:

(1)这两个函数中的线程ID对象是不透明的,不是轻易能检查的。因为线程ID是不透明的对象,所以C语言的==操作符不能用于比较 两个线程ID。

(2)gettid():是内核给线程(轻量级进程)分配的进程id,全局(所有进程中)唯一;//#include <sys/types.h>

(3)pthread_self():是在用户态实现的,获取的id实际上是主线程分配给子线程的线程描述符的地址而已,只是在当前进程空间中是唯一的。

#include <pthread.h>     #include <stdlib.h>     #include <stdio.h>     #include <sys/syscall.h>  #include <sys/types.h>  void *fun(void *arg)    {        pid_t pid;        pthread_t tid;        pid = getpid();        tid = pthread_self();        printf("%s pid is:%d ;tid is :%d\n", (char*)arg,(unsigned int)pid, (unsigned int)tid, (unsigned int)tid);       return 0;    }      int main()  {      char *s = "son thread";    pthread_t thread;    pthread_create(&thread, NULL, fun, s);        printf("in main thread_id is :%d\n",thread);      printf("in main pid is:%d ;tid is: %d \n",(unsigned int)getpid(),(unsigned int)pthread_self(),(unsigned int)pthread_self());      sleep(3);      return 0;  }

2,线程执行顺序

(1)线程的优先级无法保障线程的执行次序。只不过优先级高的线程获取 CPU 资源的概率大一点而已.

(2)setitimer()和signal()。可以精确控制线程的运行时间。
   如果没有设置条件,是不能保证线程运行次序的,操作系统会自行随机安排


原创粉丝点击