Linux多线程编程——线程的创建与退出

POSIX线程标准:该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程。Windows操作系统也有其移植版pthreads-win32。虽说现在c++11也把线程加入了标准库,但需要gcc4.8版本以上的编译器才能很好的支持,所以这里我们仍然学习posix线程标准,而且两者相差不大,学习多线程,主要是学习如何解决并发问题,如何解决多线程程序之间的同步和互斥问题。

线程概念:

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。——百度百科
学习编程最好是动手写代码,下面我会列出一些关于线程操作的api,并通过例子演示关于多线程程序如何写以及如何解决多线程程序之间的同步和互斥问题。
线程ID数据类型:pthread_t 线程属性类型:pthread_attr_t 
#include <pthread.h>
int              pthread_equal(pthread_t tid1,pthread_t tid2); //判断2个线程ID是否相同,若是返回非0数值,否则返回0
pthread_t  pthread_self(void)                                                //获得线程ID
 
线程创建
int pthread_create(pthread_t *restrict tidp,                           
         const pthread_attr_t * restrict attr,            
         void *(*start_rtn)(void *),                           
         void *restrict arg);    
                                  
创建线程,restrict关键字,表明指针所指向的内容,不能通过除此指针之外的其他直接或间接的方式修改,attr参数用来设置线程属性,一般设为NULL,创建一个具有默认属性的线程,start_rtn线程调用的函数,arg表示线程调用的函数的参数,在这个函数返回之前新线程可能已经开始运行了,创建一个线程后,也可能主线程已经结束了,新线程还没开始执行,整个进程就可能已经终止了成功返回0.
 
线程终止
void pthread_exit(void *rval_ptr);  
//终止线程,rval_ptr用来设置线程退出时的返回值,与return作用类似但有不同return不会调用清理程序,而exit会。
 
int pthred_join(pthread_t thread,void **rval_ptr);
//等待线程终止并获得线程的退出状态,rval_ptr用来获得线程退出值,若设为NULL,则只等待线程退出。注意指针指向的内存的生命周期,成功返回0
 
int pthread_cancel(pthread_t tid);                
//使用该函数表明希望线程退出,这时,被取消的线程会在某个时间,调用线程清理处理程序,就像进程退出时会调用某些函数完成清理工作
 
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
 //为线程注册清理程序,在线程退出时调用,先注册的后调用,与atexit函数类似
 
void pthread_cleanup_pop(int execute);  
//取消上一个注册的清理程序一般设为0
 
在默认情况下,线程的终止状态会保存直到对该线程调用pthread_join,如果线程已经被分离,线程的底层存储资源可以在线程终止时立即被收回。在线程分离后不能调用pthread_join,可以调用pthread_detach分离线程
int pthread_detach(pthread_t tid);
代码演示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void cleanup(void *arg)
{
    printf("cleanup: %s\n",(char *)arg);
}

void *thr_fn1(void *arg)
{
    printf("thread 1 start \n");
    pthread_cleanup_push(cleanup,"thread 1 first handler");
    pthread_cleanup_push(cleanup,"thread 1 second handler");
    printf("thread 1 push complete\n");
    if(arg)
        return ((void *)1);              //这里是return,注册的清理函数不会执行
    
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    return ((void *)1);
}

void *thr_fn2(void *arg)
{
    printf("thread 2 start \n");
    pthread_cleanup_push(cleanup,"thread 2 first handler");
    pthread_cleanup_push(cleanup,"thread 2 second handler");
    printf("thread 2 push complete\n");
    if(arg)
        pthread_exit((void *)2);     //这里是pthread_exit,清理函数会执行
    
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    pthread_exit((void *)2);
}

int main()
{
    int err;
    pthread_t tid1,tid2;
    void *tret;
    err=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
    if(err!=0)
    {
        perror("pthread_create");
        exit(-1);
    }

    err=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
    if(err!=0)
    {
        perror("pthread_create");
        exit(-1);
    }

    err=pthread_join(tid1,&tret);
    if(err!=0)
    {
        perror("pthread_join");
        exit(-1);
    }
    printf("thread1 exit code is %ld\n",(long)tret);

    err=pthread_join(tid2,&tret);
    if(err!=0)
    {
        perror("pthread_join");
        exit(-1);
    }
    printf("thread2 exit coid is %ld\n",(long)tret);
    exit(0);
}

 线程属性

 

posted @ 2017-08-22 19:37  CodeUniverse  阅读(8576)  评论(0编辑  收藏  举报