pthread 入门

来源:互联网 发布:js怎么设置按钮被点击 编辑:程序博客网 时间:2024/06/07 03:00

pthread 为POSIX线程库,windows和linux皆可用。
//例子来源教材,百度文库,以及csdn blog
1. 路径为/lib/x86_64-linux-gnu/, libpthread-2.15.so
这里写图片描述
这些lib 有不同的颜色。颜色的区别是什么?
libpci.so.3.1.8 和libpci.so.3 的区别是什么?
这里写图片描述
颜色不同,代表文件类型不同。用ll 查看。

-代表普通文件,白色l代表软链接文件,蓝色 还有绿色,代表具有可执行权限

关于蓝色软链接,以及lib*.so.*后面的数字,代表版本号。
当安装软件时,如果安装了这些同类库,但是版本不同,如果高版本可以兼容旧版本,则创建一个旧版本的软链接 ,不再创建新文件。
2. 线程的概念
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
一个进程是一个复合的实体,可以分为两个部分:线程集合 + 资源集合。
使用多线程一般有两个不同的目的:
一是把程序细分成几个功能相对独立的模块,防止其中一个功能模块阻塞导致整个程序假死(GUI程序是典型)(多任务
另一个就是提高运行效率,比如多个核同时跑,或者单核里面,某个线程进行IO操作时,另一个线程可以同时执行(并发)。
posix pthread 库

// 创建线程#include <pthread.h>int pthreat_t pthread_creat(pthread_t *thread,pthread_attr_t * attr,void *(*start_routine)(void *),void *arg)//typedef unsigned long int pthread_t//void * arg 用来向*start_routine 传参//pthread_attr_t attr 指定线程属性,可以默认为NULL//执行成功返回0,失败返回非零值。//获得线程idpthread_t pthread_self(); //无线,线程内部使用//退出    1 调用函数执行结束后自动退出    2 使用函数退出    void pthread_exit(void* retval) // 在想中途退出时,有用。成功返回0,失败-1。 返回值保存在retval 指针中。

demo1.cpp

#include <iostream>#include <pthread.h>using namespace std;#define NUM_THREADS 5void* say_hello(void* args){    cout << "___HELLO___ "<< endl;    pthread_exit(0);}int main(){    pthread_t tids[NUM_THREADS];    for(int i = 0; i < NUM_THREADS; i++)    {    int ret = pthread_create(&tids[i],NULL,say_hello,(void *)&i);    if(ret != 0)        {        cout << "Pthread create error !!!!"<< i <<"____"<< ret << endl;        }    else    {        cout << "main___"<< endl;    }}    pthread_exit(NULL);////等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;}// g++ -o 1 1.cpp -lpthread   #此处-l指定库要放在后面,放在-o前面,会说ld 链接错误!! gcc g++ 这是个使用细节。

运行结果:

main___main___main___main___main______HELLO___ ___HELLO___ ___HELLO___ ___HELLO___ ___HELLO___ 

————————结果表明,主线程运行的速度远远比线程速度快多了。并且新线程和主线程是并发的。
demo2.c

#include <pthread.h>#include <stdio.h>void print_msg(char *ptr){    int retval;    printf("Thread_id is %lx______%s\n",pthread_self(),ptr);    pthread_exit(&retval);}/*或者void print_msg(void *ptr){    int retval;    printf("Thread_id is %lx______%s\n",pthread_self(),(char*)ptr);    pthread_exit(&retval);}*/int main(){    pthread_t thread1,thread2;    char* msg1= "Hello ";    char* msg2 = "WORLD ";    printf("Let's go    \n");    pthread_create(&thread1,NULL,(void*)(&print_msg),(void *)msg1);    pthread_create(&thread2,NULL,(void*)(&print_msg),(void* )msg2);    // 线程传参    sleep(2);    return 0;}

运行结果:

Let's go    Thread_id is 7fb19a42f700______WORLD Thread_id is 7fb19ac30700______Hello 

——————————2个新线程的执行顺序是反的,什么鬼!!
demo3.cpp 线程如何调用类中函数——static

#include <iostream>#include <pthread.h>using namespace std;class hello{    public:    static void* sayhello(void* args) //static         {        cout << "hello class..."<< endl;        }};int main(){    pthread_t pid[5];    for(int i =0; i < 5; i++)    {    int ret = pthread_create(&pid[i],NULL,hello::sayhello,NULL);    if(ret != 0)        cout << "Pthread_create failed .."<< endl;    }    pthread_exit(NULL);////等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;    return 0;}

demo3.cpp 线程退出状态和线程属性

#include <iostream>#include <pthread.h>using namespace std;#define NUM_THREADS 5void* say_hello(void* args){    cout << "___HELLO___ "<< *((int*)args) << endl;    int status = 10 + *((int*)args); // 将参数+10    pthread_exit((void*)status);//由于线程创建时提供了Jointable参数,这里可以在退出时添加退出信息;    //status提供给主程序提取该线程退出线程的结束信息}int main(){    pthread_t tids[NUM_THREADS];    int indexs[NUM_THREADS];    pthread_attr_t attr;//第一步声明:线程属性,用于pthread_create创建时加入参数    pthread_attr_init(&attr);//第二部:线程属性初始化    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);    //第三步:设置你要执行线程属性参数,该参数表明该线程是可以Join连接的,    //join 表示主程序可以等线程结束后再执行,实现了**主程序和线程同步功能**    for(int i = 0; i < NUM_THREADS; i++)    {    indexs[i]= i;       int ret = pthread_create(&tids[i],NULL,say_hello,(void *)&(indexs[i]));//4 arguments    if(ret != 0)        {        cout << "Pthread create error !!!!"<< i <<"____"<< ret << endl;        }    else        {        cout << "main___"<< endl;        }    }    pthread_attr_destroy(&attr); //创建线程后,该参数已经结束使命,必须销毁,防止内存泄漏。    void* status;    for(int i =0;i< NUM_THREADS;i++)    {        int ret = pthread_join(tids[i],&status);//前面创建了线程,这里主程序想要join 每个线程,然后取得每个线程的退出信息status.        if(ret !=0)            cout << "pthread_join_error: error code : "<< ret << endl;        else            cout << "pthread_join get status: " << (long )status << endl;    }    pthread_exit(NULL);}

运行结果

main___main___main___main___main______HELLO___ 4___HELLO___ 3___HELLO___ 2___HELLO___ 1___HELLO___ 0pthread_join get status: 10pthread_join get status: 11pthread_join get status: 12pthread_join get status: 13pthread_join get status: 14

——————————线程执行顺序依然是反的!
——————————主程序第一,然后是线程回调,最后是join 部分代码(主程序)(这一部分顺序确是对的,首先创建的线程遍历。)。
- joinable 和 detached 可结合 和 分离的
任何一个时间点,线程是可结合的joinable 或者分离的 detached. 线程的默认状态是非分离状态(即Joinable,需要回收)
Joinable:
能够被其他线程收回资源和杀死
在被其他线程回收前,它的存储器资源(如栈)是不释放的。
detached:
不能被其他线程回收或者杀死
它的存储器资源在它终止时由系统自动释放

可结合线程(Joinable):    线程的**分离状态**决定一个线程以什么样的方式来终止自己。    默认线程我们采用了线程非分离状态(即可结合的,joinable,需要回收)    这种情况下,原有的线程等待创建的线程结束;**只有当pthread_join()函数返回时,创建的线程才算终止**,**才能释放自己占用的系统资源**。    主线程需要**明确执行等待**操作,在子线程结束后,主线程的等待操作执行完毕,子线程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。分离线程(detached):    分离线程不是这样子的,它没有被其他的线程所等待。    自己运行结束了,线程也就终止了,马上释放系统资源。线程的分离状态设置    函数 pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate)    第二个参数值选项为宏PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)注意点:    如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在 pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用 pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。    如果创建Joinable 线程,那就在主程序中必须pthread_join() 进行资源回收。
#include <pthread.h>void pthread_exit(void *retval);void pthread_join(pthread_t th,void **thread_return);//主线程挂起等待th结束//*thread_return=retval; 新线程结束返回状态,传给*thread_returnint pthread_detach(pthread_t th);

这里写图片描述
join()挂起

#include <pthread.h>#include <stdio.h>void print_msg(char *ptr){    int i;    for( i = 0; i < 10; i++)        printf("_%s_",ptr);}int main(){    pthread_t thread1,thread2;    int i ,j;    void* retval;    char* msg1= " Hello ";    char* msg2 = " WORLD ";    printf("****Let's go*** \n");    pthread_create(&thread1,NULL,(void*)(&print_msg),(void *)msg1);    pthread_create(&thread2,NULL,(void*)(&print_msg),(void* )msg2);    pthread_join(thread1,&retval);    printf("#####################################\n");    printf("*************************************\n");    pthread_join(thread2,&retval);    printf("+++++++++++++++++++++++++++++++++++++\n");    printf("ALL DONE !! MAIN");    return 0;}

运行结果:

robot@ubuntu:~/Documents/posix/1$ ./demo1join ****Let's go*** _ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello _#####################################*************************************+++++++++++++++++++++++++++++++++++++
  1. 优先级使用数据结构

//参考自a_ran的csdn

struct sched_param{    int __sched_priority; //所要设定的线程优先级  1 -99 , 数字越大,优先级越高。}
Linux内核的三种调度策略:

  1,SCHED_OTHER 分时调度策略,(不支持优先级)
  2,SCHED_FIFO实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃
  3,SCHED_RR实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平
  设置和获取优先级的函数
  

    int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);   int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);     param.sched_priority = 51; //设置优先级

系统默认创建线程使用的是SCHED_OTHER。 没有优先级。若要更改线程的调度策略,通过如下函数。

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

测试程序:

 #include <stdio.h>#include <pthread.h>#include <sched.h>#include <assert.h>static int get_thread_policy(pthread_attr_t *attr){  int policy;  int rs = pthread_attr_getschedpolicy(attr,&policy);  assert(rs==0);  switch(policy)  {  case SCHED_FIFO:    printf("policy= SCHED_FIFO\n");    break;  case SCHED_RR:    printf("policy= SCHED_RR");    break;  case SCHED_OTHER:    printf("policy=SCHED_OTHER\n");    break;  default:    printf("policy=UNKNOWN\n");    break;  }  return policy;}static void show_thread_priority(pthread_attr_t *attr,int policy){  int priority = sched_get_priority_max(policy);  assert(priority!=-1);  printf("max_priority=%d\n",priority);  priority= sched_get_priority_min(policy);  assert(priority!=-1);  printf("min_priority=%d\n",priority);}static int get_thread_priority(pthread_attr_t *attr){  struct sched_param param;  int rs = pthread_attr_getschedparam(attr,&param);  assert(rs==0);  printf("priority=%d",param.__sched_priority);  return param.__sched_priority;}static void set_thread_policy(pthread_attr_t *attr,int policy){  int rs = pthread_attr_setschedpolicy(attr,policy);  assert(rs==0);  get_thread_policy(attr);}int main(void){  pthread_attr_t attr;  struct sched_param sched;  int rs;  rs = pthread_attr_init(&attr);  assert(rs==0);  int policy = get_thread_policy(&attr);  printf("Show current configuration of priority\n");    show_thread_priority(&attr,policy);  printf("show SCHED_FIFO of priority\n"); show_thread_priority(&attr,SCHED_FIFO);  printf("show SCHED_RR of priority\n");  show_thread_priority(&attr,SCHED_RR);  printf("show priority of current thread\n");  int priority = get_thread_priority(&attr);  printf("Set thread policy\n");  printf("set SCHED_FIFO policy\n");  set_thread_policy(&attr,SCHED_FIFO);  printf("set SCHED_RR policy\n");  set_thread_policy(&attr,SCHED_RR);  printf("Restore current policy\n");  set_thread_policy(&attr,policy);  rs = pthread_attr_destroy(&attr);  assert(rs==0);  return 0;}

运行结果:

policy=SCHED_OTHERShow current configuration of prioritymax_priority=0min_priority=0show SCHED_FIFO of prioritymax_priority=99min_priority=1show SCHED_RR of prioritymax_priority=99min_priority=1show priority of current threadpriority=0Set thread policyset SCHED_FIFO policypolicy= SCHED_FIFOset SCHED_RR policypolicy= SCHED_RRRestore current policypolicy=SCHED_OTHER

不同线程调度方案和优先级。
测试程序:

#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>void Thread1(){  sleep(1);  int i,j;  int policy;  struct sched_param param;  pthread_getschedparam(pthread_self(),&policy,&param);  if(policy == SCHED_OTHER)    printf("SCHED_OTHER\n");  if(policy == SCHED_RR);  printf("SCHED_RR 1 \n");  if(policy==SCHED_FIFO)    printf("SCHED_FIFO\n");  for(i=1;i<10;i++)  {    for(j=1;j<5000000;j++)    {    }    printf("thread 1\n");  }  printf("Pthread 1 exit\n");}void Thread2(){  sleep(1);  int i,j,m;  int policy;  struct sched_param param;pthread_getschedparam(pthread_self(),&policy,&param); if(policy == SCHED_OTHER)    printf("SCHED_OTHER\n");  if(policy == SCHED_RR);  printf("SCHED_RR\n");  if(policy==SCHED_FIFO)    printf("SCHED_FIFO\n");  for(i=1;i<10;i++)  {    for(j=1;j<5000000;j++)    {    }    printf("thread 2\n");  }  printf("Pthread 2 exit\n");}void Thread3(){  sleep(1);  int i,j;  int policy;  struct sched_param param;pthread_getschedparam(pthread_self(),&policy,&param); if(policy == SCHED_OTHER)    printf("SCHED_OTHER\n");  if(policy == SCHED_RR)    printf("SCHED_RR \n");  if(policy==SCHED_FIFO)    printf("SCHED_FIFO\n");  for(i=1;i<10;i++)  {    for(j=1;j<5000000;j++)    {    }    printf("thread 3\n");  }  printf("Pthread 3 exit\n");}int main(){  int i;  i = getuid();  if(i==0)    printf("The current user is root\n");  else    printf("The current user is not root\n");  pthread_t ppid1,ppid2,ppid3;  struct sched_param param;  pthread_attr_t attr,attr1,attr2;  pthread_attr_init(&attr1);pthread_attr_init(&attr);pthread_attr_init(&attr2);  param.sched_priority = 51; pthread_attr_setschedpolicy(&attr2,SCHED_RR); pthread_attr_setschedparam(&attr2,&param); pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);//要使优先级其作用必须要有这句话 param.sched_priority = 21; pthread_attr_setschedpolicy(&attr1,SCHED_RR); pthread_attr_setschedparam(&attr1,&param); pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED); pthread_create(&ppid3,&attr,(void *)Thread3,NULL); pthread_create(&ppid2,&attr1,(void *)Thread2,NULL); pthread_create(&ppid1,&attr2,(void *)Thread1,NULL); pthread_join(ppid3,NULL); pthread_join(ppid2,NULL); pthread_join(ppid1,NULL); pthread_attr_destroy(&attr2); pthread_attr_destroy(&attr1); return 0;}

运行结果:

robot@ubuntu:~/Documents/posix/2$ ./thread2 The current user is not rootSCHED_OTHERthread 3thread 3thread 3thread 3thread 3thread 3thread 3thread 3thread 3Pthread 3 exitrobot@ubuntu:~/Documents/posix/2$ sudo ./thread2 [sudo] password for robot: The current user is rootSCHED_RR 1 thread 1thread 1thread 1thread 1thread 1thread 1thread 1thread 1thread 1Pthread 1 exitSCHED_RRthread 2thread 2thread 2thread 2thread 2thread 2thread 2thread 2thread 2Pthread 2 exitSCHED_OTHERthread 3thread 3thread 3thread 3thread 3thread 3thread 3thread 3thread 3Pthread 3 exitrobot@ubuntu:~/Documents/posix/2$
  1. 互斥锁和条件变量
    mutual exclusion 互相排斥,互斥锁锁的是线程,而保护公共区域数据,是因为多个线程均使用了互斥锁。
#include <stdio.h>#include <pthread.h>#define FALSE 0#define TRUE 1void readfun();void writefun();char buffer[256]; // 公共数据区int buf_has_item = 0;//设置数据区的标志位int retFLAG = FALSE ;//pthread_mutex_t mutex;//互斥锁全局变量int main(){    pthread_t reader;    pthread_mutex_init(&mutex,NULL);    pthread_create(&reader,NULL,(void *)(&readfun),NULL);    writefun();// 先写再读,该处write 速度比新线程要快,所以先看writefun()    return 0;}void readfun(){    while(TRUE)    {        if(retFLAG)            return;        pthread_mutex_lock(&mutex);        if(buf_has_item== 1)        {            printf("%s",buffer);            buf_has_item = 0;        }        pthread_mutex_unlock(&mutex);    }}void writefun(){    int i = 0;//这个i 是和while 要进行遍历,但是下面的if--return ,限制了循环次数。while(1)---return;    //return 的作用是退出循环体所在的函数,相当于结束该方法。    while(TRUE)    {        if(i == 10)        {            retFLAG = TRUE;            return;//return 和循环没关系,就是跳出该函数        }        pthread_mutex_lock(&mutex); //先上锁,新线程阻塞!        if(buf_has_item == 0)//判断状态位置        {            sprintf(buffer,"This is %d\n",i++);            buf_has_item = 1;  //该状态位为 readfun()判断使用。        }    pthread_mutex_unlock(&mutex);    }}

结果为:

robot@ubuntu:~/Documents/posix/3$ ./mutex This is 0This is 1This is 2This is 3This is 4This is 5This is 6This is 7This is 8   //共循环9次。i++ 0-8;如果writefun()中sprintf改成(++i)就会是循环1-9次
  1. 条件变量
    互斥锁只有两个状态,不能满足常用的使用方式,所以条件变量和互斥锁常常搭配使用,控制线程间的工作方式
//初始化条件变量pthread_cond_t cond;int pthread_cond_init(pthread_cond_t *cond,const pthread_cond_attr *attr);int pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_wait(pthread_cond_t *cond,pthread_murex_t *mutex);//函数将阻塞,直到条件变量获得信号或者经过abstime指定的时间。int pthread_cond_timewait(pthread_cond_t *cond,pthread_murex_t *mutex,const struct timespec* abstime);//发送信号int pthread_cond_signal(pthread_cond_t *cond)//使得所有关于由参数cond 指向的条件变量阻塞的线程退出阻塞状态。参数没有mutex,并不指向使用锁的且阻塞的线程。int pthread_cond_broadcast(pthread_cond_t *cond)

条件变量demo

#include <pthread.h>#include <iostream>using namespace std;#define BOUNDARY 5 //全局变量int task = 10;pthread_mutex_t task_mutex;//锁pthread_cond_t task_cond;//条件变量,设为全局void* say_hello2(void* args){    pthread_t pid = pthread_self();//获得线程资源编号    cout<< "["<< pid << "] hello in thread" << *((int*)args)<< endl;    bool is_signaled = false ; //随便设置的标志位,用于条件切换,发送信号    while(1)    {        pthread_mutex_lock(&task_mutex);//先锁,再判断。        if(task > BOUNDARY)        {            cout << "["<<pid <<"] take task :"<< task << "in thread"<<*((int*)args) << endl;            --task;        }        else if (!is_signaled)        {            cout << "["<<"] pthread_cond_signal in thread " << *((int *)args)<< endl;            pthread_cond_signal(&task_cond);//重点发送信号            is_signaled = true ;        }        pthread_mutex_unlock(&task_mutex);        if(task == 0)// 用于跳出while            break;    }}void* say_hello1(void* args){    pthread_t pid = pthread_self();    cout << "["<<pid <<"] hello in thread "<< *((int*)args)  << endl;    while(1)    {        pthread_mutex_lock(&task_mutex);        if(task > BOUNDARY)        {            cout <<"["<< pid <<"] pthread_cond_wait in thread" << *((int*) args) << endl;            pthread_cond_wait(&task_cond,&task_mutex);//重点,收到信号前阻塞        }        else        {            cout << "["<< pid << "] take task:"<< task << "in thread "<< *((int* )args) << endl;            --task;        }        pthread_mutex_unlock(&task_mutex);        if(task ==0)//小于5时,会空循环5次,直到==0,break            break;    }}int main(){    pthread_attr_t attr;    pthread_attr_init(&attr);    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);//为下面Join    pthread_mutex_init(&task_mutex,NULL);    pthread_cond_init(&task_cond,NULL);    pthread_t tid1,tid2;    int index1 =1, index2 =2 ;    int ret1 = pthread_create(&tid1,&attr,say_hello1,(void*)&index1);    if(ret1 != 0)        cout << "pthread 1 create failed ! error code is "<< ret1 << endl;    int ret2 = pthread_create(&tid2,&attr,say_hello2,(void*)&index2);    if(ret2 !=0)        cout << "pthread 2 create failed ! error code is "<< ret2 << endl;    pthread_join(tid1,NULL);    pthread_join(tid2,NULL);    pthread_attr_destroy(&attr);    pthread_mutex_destroy(&task_mutex);    pthread_cond_destroy(&task_cond);    return 0;}

运行结果:

robot@ubuntu:~/Documents/posix/3$ ./cond1 [140355188872960] hello in thread2[140355188872960] take task :10in thread2[140355188872960] take task :9in thread2[140355188872960] take task :8in thread2[140355188872960] take task :7in thread2[140355188872960] take task :6in thread2[] pthread_cond_signal in thread 2[140355197265664] hello in thread 15[140355197265664] take task:5in thread 1[140355197265664] take task:4in thread 1[140355197265664] take task:3in thread 1[140355197265664] take task:2in thread 1[140355197265664] take task:1in thread 1