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