linux多线程心得


—多线程—

​ 在Linux下线程是最小的执行单位,调度的基本单位。

1. 控制原语对比

进程 线程
fork() pthread_create() //创建线程
exit() pthread_exit() //退出线程
wait() pthread_join() //回收线程
kill() pthread_cancel() //取消线程
getpid() pthread_self () //获取当前线程
pthread_cond_wait(); //阻塞等待唤醒
pthread_cond_signal(); //唤醒一个线程
pthread_mutex_lock(); //加锁

阻塞函数:

pthread_join();

pthread_mutex_lock();

pthread_cond_wait();

注意:

1、如果 n次调用pthread_cond_signal() 。 表明唤醒n个线程,而pthread_cond_wait()处只能处理一个线程,其余线程在pthread_cond_wait()处等待抢锁。

2、如果多线程共用一把锁,锁里的内容不管是什么,加锁后其他线程不能访问。

1.1 pthread_create()函数

创建一个新线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

​ 参数:
​ pthread_t:当前Linux中可理解为:typedef unsigned long int pthread_t;
​ 参数1:传出参数,保存系统为我们分配好的线程ID
​ 参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
​ 参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
​ 参数4:线程主函数执行期间所使用的参数,如要传多个参数, 可以用结构封装。

​ 返回值:
​ 成功:0; 失败:错误号 —–Linux环境下,所有线程特点,失败均直接返回错误号。

1.2 pthread_exit()函数

—将单个线程退出

void pthread_exit(void *retval);

​ 参数:
​ retval表示线程退出状态,通常传NULL。

1.3 pthread_join()函数

—阻塞等待线程退出,获取线程退出状态

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

​ 参数:
​ thread:线程ID (【注意】:不是指针);
​ retval:存储线程结束状态。

​ 返回值:
​ 成功:0;失败:错误号

1.4 pthread_cancel()函数

—杀死(取消)线程

int pthread_cancel(pthread_t thread); 

​ 返回值:
​ 成功:0;失败:错误号

1.5 代码实例

#include <pthread.h>
#include <iostream>
using namespace std;


void *thr_fun(void *p)
{

    cout<<" i'm pthread!"<<endl;
       //退出线程
    pthread_exit(NULL);
    //return NULL;

}

int main()
{

cout<<"begin"<<endl;
pthread_t tid;

//创建线程
pthread_create(&tid,NULL,thr_fun,NULL);
//回收线程
pthread_join(tid,NULL);

cout<<"end!"<<endl;

return 0 ;

2. 线程基础练习

2.1 写一段简单的程序,启动两个线程交替打印1–100

第一种方法: 加两把锁,锁住第一个,解第二个。

#include <cstdio>
#include <iostream>
using namespace std;
#include <pthread.h>
#include <string.h>
#include <unistd.h>


int num = 1; 
pthread_mutex_t mut1;
pthread_mutex_t mut2;
pthread_cond_t cond;

//写一段简单的程序,启动两个线程交替打印1–100
void* worker1(void * ptr)
{
    while (num < 100)
    {
        

        pthread_mutex_lock(&mut1);
    
        cout << "A :" << num << endl;
        num++;
        pthread_mutex_unlock(&mut2);
    }
    pthread_exit(NULL);
}
void* worker2(void* ptr)
{
    while (num < 100)
    {
        pthread_mutex_lock(&mut2);

        cout << "B :" << num << endl;
        num++;
        pthread_mutex_unlock(&mut1);
    }
    pthread_exit(NULL);
}

int main()
{
    pthread_t tid1;
    pthread_t tid2;


    pthread_mutex_init(&mut1,NULL);
    pthread_mutex_init(&mut2, NULL);
    pthread_cond_init(&cond,NULL);
    
    pthread_mutex_lock(&mut2);
    pthread_create(&tid1,NULL,worker1,NULL );
    pthread_create(&tid2, NULL, worker2, NULL);


    sleep(2);
    
    return 0;
}

第二种方法:用一个标记FLAG来交替打

2.2 编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C, 每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC…依次递推。

与第一题类似。

第一种方法:用标记FLAG

//编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C, 每个线程将自己的ID在屏幕上打印10遍,
//要求输出结果必须按ABC的顺序显示;如:ABCABC…依次递推。

int num = 1; 
pthread_mutex_t mut;
pthread_cond_t cond;
int flag = 1;

void* worker1(void * ptr)
{
    while (num <= 30)
    {
        if (flag == 1)
        {
            pthread_mutex_lock(&mut);

            cout << "A";
            num++;
            flag = 2;
            pthread_mutex_unlock(&mut);
        }
    
    }
    pthread_exit(NULL);

}
void* worker2(void* ptr)
{
    while (num <= 30)
    {
        if (flag == 2)
        {
            pthread_mutex_lock(&mut);

            cout << "B" ;
            num++;
            flag = 3;
            pthread_mutex_unlock(&mut);
        }
    
    }
    pthread_exit(NULL);

}

void* worker3(void* ptr)
{
    while (num <= 30)
    {
        if (flag == 3)
        {
            pthread_mutex_lock(&mut);

            cout << "C";
            num++;
            flag = 1;
            pthread_mutex_unlock(&mut);
        }
    
    }
    pthread_exit(NULL);

}

int main()
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;


    pthread_mutex_init(&mut,NULL);
    pthread_cond_init(&cond,NULL);
    
    pthread_create(&tid1,NULL,worker1,NULL );
    pthread_create(&tid2, NULL, worker2, NULL);
    pthread_create(&tid3, NULL, worker3, NULL);

    sleep(2);
    
    return 0;

}

2.3 顺序打出ABCD

思路: 先将4个线程全部加锁,然后解下个锁。

#include <stdlib.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace std;
#include <iostream>
#include <string.h>

#define N  4

pthread_mutex_t mut[N];


class tmp
{
public:
    tmp(int i) {
        this->n = i;
    }

    int n;

};

void* worker1(void* ptr)
{

    char num = ((tmp*)ptr)->n + 'a';
    
    for (int i = 0; i < 100; ++i)
    {
        pthread_mutex_lock(mut + ((tmp*)ptr)->n);
    
        cout << num;
        pthread_mutex_unlock(mut + (((tmp*)ptr)->n+1 )%N);
    
    }


    pthread_exit(NULL);

}


int main()
{
    pthread_t* tid1 = new pthread_t[N];


    memset(tid1, 0, sizeof(pthread_t) * N);
    tmp* tp;


    for (int i = 0; i < N; ++i)
    {
        tp = new tmp(i);
        pthread_mutex_init(&mut[i], NULL);
        pthread_mutex_lock(mut+i);
        pthread_create(tid1+i, NULL, worker1, tp);
    }
      
    pthread_mutex_unlock(mut+0);


    sleep(2);
    
    return 0;

}

3. 案例实例进阶

案例: 在 20000000 ~ 20000200 数里找出所有的质数。

3.1 单进程单线程的质数筛选

#include <iostream>
using namespace std;
#include <pthread.h>

#define LEFT  20000000
#define RIGHT 20000200

int main()
{
    for(int i =  LEFT; i<=RIGHT;++i)
    {    
        int mark  = 1  ;
        for(int j =  2; j<i/2 ; ++j)
        {
            if(i % j  == 0)
            {
                mark = 0;
                break;
                
            }
        }
        if(mark)
        {
            cout<<i<<" is a primer" <<endl;
        }
    }

    exit(0);
}

3.2 为201个数分配201个线程进行筛选

​ 升级版本1.0 为每个数分配一个线程。值得注意的是不能直接在创建线程里传入地址 &tp , 这样会指向同一个地址,因此做了一个结构体tmp整体传入。

#include <iostream>
using namespace std;
#include <pthread.h>
#include <bits/stdc++.h>

#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)

 class tmp
 {
 public:
     tmp(int i)
     {
         this->n = i;
     }
     int n ;
 };

void *thr_primer(void *p)
{        

    int mark  = 1;
    int i;
    i =((tmp *)p)->n;
    free(p);
    for(int j = 2 ; j < i/2 ;++j)
    {
        if( i % j == 0)
        {
            mark = 0;
            break;
        }
    }
    if(mark)
    {
        cout<< i <<" is a primer"<<endl;
    }
    //线程退出
    pthread_exit(NULL);

}

int main()
{

    pthread_t tid[THRNUM];    
    int err;
    tmp *tp;
    
    //循环创建线程
    for(int i = LEFT; i<=RIGHT ;++i)
    {
         
        tp = new tmp(i);
        
        //tp 为传入的每个数的结构体
        err = pthread_create(tid+(i-LEFT),NULL,thr_primer,tp);
        if(err)
        {
            fprintf(stderr,"pthread_create():%s\n",strerror(err));
            exit(1);        
        }
    }

    //线程回收
    for(int i = LEFT;i<=RIGHT;++i)
        pthread_join(tid[i-LEFT],NULL);



    exit(0);

}

3.3 按照进程池的形式创建4个线程进行筛选

​ 升级版本2.0 用互斥量(pthread_mutex_t)为4个线程按照进程池的形式进行筛选
​ num = 0 –任务已抢
​ num = -1 –任务分配完毕
​ num>0 –待抢任务

#include <iostream>
using namespace std;
#include <pthread.h>

#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM 4

//num = -1 为任务抢完, num = 0 待抢  num = LEFT~RIGHT 为抢任务
static int  num = 0 ;

static pthread_mutex_t mut  = PTHREAD_MUTEX_INITIALIZER;


void *thr_work(void *p)
{


    int mark;
    int i ; 
    while(1)
    {
        pthread_mutex_lock(&mut);
        while( num == 0 )
        {
            pthread_mutex_unlock(&mut);
            sched_yield();
            pthread_mutex_lock(&mut);
        }
        
        if(num == -1)
        {
            pthread_mutex_unlock(&mut);
            break;
        }
        
        i = num;
    
        num = 0 ;
        pthread_mutex_unlock(&mut);
    
        mark  = 1;
        for(int j = 2  ; j< i/2;++j)
        {
            if(i % j == 0)
            {
                mark = 0 ; 
                break;
            }
        }

        if(mark)
        {
            cout << i << " is a priemr " <<endl;
        }
    
    }


    pthread_exit(NULL);

}


int main()
{
    
    pthread_t tid[THRNUM];
    
    for(int i = 0 ; i< THRNUM; ++i)
    {
        pthread_create(tid+i,NULL,thr_work,NULL);
    }


    for(int i = LEFT ; i <= RIGHT ; ++i)
    {
        
        //加锁抢任务
        pthread_mutex_lock(&mut);    
        //如果有任务正在进行
        while(num != 0 )
        {
            pthread_mutex_unlock(&mut);
             //短时让出调度器
            sched_yield();
            pthread_mutex_lock(&mut);
        }
        num = i ;    
        pthread_mutex_unlock(&mut);
    }
    

    pthread_mutex_lock(&mut);
    while(num !=0)
    {
        pthread_mutex_unlock(&mut);
        sched_yield();
        pthread_mutex_lock(&mut);
    
    }
    //任务抢完
    num = -1 ; 
    pthread_mutex_unlock(&mut);


    for(int i = 0 ; i< THRNUM;++i)
        pthread_join(tid[i],NULL);
    
    pthread_mutex_destroy(&mut);
    
    exit(0);

}

3.4 在3.3的基础上加上条件变量

​ 升级版本3.0 在版本2.0的基础上加入了条件变量(pthread_cond_t ) ,避免了忙等。

#include <iostream>
using namespace std;

#include <pthread.h>

#define LEFT   30000000
#define RIGHT  30000200
#define THRNUM 4

static int num = 0 ;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;


void *thr_work(void *p)
{

    int i ;
    while(1)
    {
        pthread_mutex_lock(&mut);
        while(num == 0 )
            pthread_cond_wait(&cond,&mut);
        if(num == -1)
        {
            pthread_mutex_unlock(&mut);
            break;
        }
        
        i = num ;
        num = 0 ;
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mut);


        int mark = 1;
        for(int j = 2; j< i/2;++j)
        {
            if( i %j == 0)
            {
                mark = 0 ; 
                break;
            }
        }
        
        if(mark)
            cout<< i <<" is a primer"<<endl;
    }
    pthread_exit(NULL);

}


int main()
{

    pthread_t tid[THRNUM];
    
    for(int i = 0 ;  i<THRNUM;++i)
        pthread_create(tid+i,NULL,thr_work,NULL);
    for(int i = LEFT; i <= RIGHT;++i)
    {
        pthread_mutex_lock(&mut);
        while( num != 0 )
            pthread_cond_wait(&cond,&mut);
        num = i ;
        
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mut);
        
    }
    
    pthread_mutex_lock(&mut);
    while( num != 0 )
        pthread_cond_wait(&cond,&mut);
    num = -1 ;
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mut);
    
    for(int i = 0 ;i<THRNUM;++i)
        pthread_join(tid[i],NULL);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mut);

    exit(0);

}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 351134995@qq.com

×

喜欢就点赞,疼爱就打赏