—多线程—
 在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
 
            