POSIX线程标准:该标准定义了建立和操纵线程的一整套API。在类Unix操做系统(Unix、Linux、Mac OS X等)中,都使用Pthreads做为操做系统的线程。Windows操做系统也有其移植版pthreads-win32。虽然说如今c++11也把线程加入了标准库,但须要gcc4.8版本以上的编译器才能很好的支持,因此这里咱们仍然学习posix线程标准,并且二者相差不大,学习多线程,主要是学习如何解决并发问题,如何解决多线程程序之间的同步和互斥问题。c++
线程概念:编程
线程,有时被称为轻量级进程(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);
}
线程属性api