C++ 多线程
本文主要讲一下C++多线程
线程好处
·使用线程可以把占据长时间的程序中的任务放到后台去处理
·程序的运行速度可能加快
可以释放一些珍贵的资源如内存占用等等。
但是多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
首先 我们现在在学校使用的和大赛使用的C++编程软件一般都是codeblocks(湖南省比赛是的,其他就不知道了)
但是在CodeBlocks中间 我们是不能直接使用线程的 需要设置一下
创建线程
线程的头文件与现场创建格式
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
在这里,pthread_create
创建一个新的线程,并让它可执行。下面是关于参数的说明:
参数说明
参数 | 说明 |
---|---|
thread | 指向线程标识符指针。保存的是线程id |
attr | 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。 |
start_routine | 线程运行函数起始地址,即线程函数名。 |
arg | 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。 |
创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。
线程有创建 自然也就有结束
下面介绍一下结束线程的方法:
终止线程
使用下面的方法 我们可以结束线程
#include <pthread.h>
pthread_exit (status);
在这里,pthread_exit
用于显式地退出一个线程。通常情况下,pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。
注意,main()函数是一个进程,也是可以使用上面的函数去结束它的。如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。
下面以一个实例来说明一下main()函数是否通过 pthread_exit() 退出的不同 下面是代码
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void* say_hello(void* args)
{
cout << "Hello Runoob!" << endl;
}
int main()
{
pthread_t tids[NUM_THREADS];// 定义线程的 id 变量,多个变量使用数组
for(int i = ; i < NUM_THREADS; ++i)
{
//参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
pthread_create(&tids[i], NULL, say_hello, NULL);
}
//等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
pthread_exit(NULL);//俩次运行的不同之处在于有没有这一行
}
//有这一行的运行结果
Hello Runoob!Hello Runoob!
Hello Runoob!
Hello Runoob! Hello Runoob!
//上面是一种结果 由于多个线程之间是同步的 所以输出结果可以有多种 下面是我第二次运行的结果
Hello Runoob!Hello Runoob!
Hello Runoob!
Hello Runoob!
Hello Runoob!
//没有这一行的运行结果
Hello Runoob!
//5个线程仅仅只有一个运行完成 其他4个直接中断运行
//同样的 运行结果会有其他的情况 下面是我第二次的运行结果
Hello Runoob!Hello Runoob!
Hello Runoob!
Hello Runoob!
线程的参数传递
以下简单的实例代码使用 pthread_create() 函数创建了 5 个线程,并接收传入的参数。每个线程打印一个 "Hello Runoob!" 消息,并输出接收的参数,然后调用 pthread_exit() 终止线程。
//文件名:test.cpp
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
// 对传入的参数进行强制类型转换,由无类型指针变为整形数指针,然后再读取
int tid = *((int*)threadid);
cout << "Hello Runoob! 线程 ID, " << tid << endl;
pthread_exit(NULL);
}
int main ()
{
pthread_t threads[NUM_THREADS];
int indexes[NUM_THREADS];// 用数组来保存i的值
int rc;
int i;
for( i=; i < NUM_THREADS; i++ ){
cout << "main() : 创建线程, " << i << endl;
indexes[i] = i; //先保存i的值
// 传入的时候必须强制转换为void* 类型,即无类型指针
rc = pthread_create(&threads[i], NULL,
PrintHello, (void *)&(indexes[i]));
if (rc){
cout << "Error:无法创建线程," << rc << endl;
exit(-);
}
}
pthread_exit(NULL);
}
现在编译并执行程序,将产生下列结果:
main() : 创建线程,
main() : 创建线程,
main() : 创建线程,
main() : 创建线程,
main() : 创建线程,
Hello Runoob! 线程 ID,
Hello Runoob! 线程 ID,
Hello Runoob! 线程 ID,
Hello Runoob! 线程 ID,
Hello Runoob! 线程 ID,
向线程传递参数
这个实例演示了如何通过结构传递多个参数。您可以在线程回调中传递任意的数据类型,因为它指向 void,如下面的实例所示:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
struct thread_data{
int thread_id;
char *message;
};
void *PrintHello(void *threadarg)
{
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
cout << "Thread ID : " << my_data->thread_id ;
cout << " Message : " << my_data->message << endl;
pthread_exit(NULL);
}
int main ()
{
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc;
int i;
for( i=; i < NUM_THREADS; i++ ){
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;
td[i].message = "This is message";
rc = pthread_create(&threads[i], NULL,
PrintHello, (void *)&td[i]); //传入到参数必须强转为void*类型,即无类型指针
if (rc){
cout << "Error:unable to create thread," << rc << endl;
exit(-);
}
}
pthread_exit(NULL);
}
当上面的代码被编译和执行时,它会产生下列结果:
main() : creating thread,
main() : creating thread,
main() : creating thread,
main() : creating thread,
main() : creating thread,
Thread ID : Message : This is message
Thread ID : Message : This is message
Thread ID : Message : This is message
Thread ID : Message : This is message
Thread ID : Message : This is message
连接和分离线程
我们可以使用以下两个函数来连接或分离线程:
pthread_join (threadid, status)
pthread_detach (threadid)
pthread_join()
子程序阻碍调用程序,直到指定的 threadid
线程终止为止。当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或可分离的(detached)。只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连接。
这个实例演示了如何使用 pthread_join() 函数来等待线程的完成。
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
using namespace std;
#define NUM_THREADS 5
void *wait(void *t)
{
int i;
long tid;
tid = (long)t;
sleep();
cout << "Sleeping in thread " << endl;
cout << "Thread with id : " << tid << " ...exiting " << endl;
pthread_exit(NULL);
}
int main ()
{
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
// 初始化并设置线程为可连接的(joinable)
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for( i=; i < NUM_THREADS; i++ ){
cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], NULL, wait, (void *)i );
if (rc){
cout << "Error:unable to create thread," << rc << endl;
exit(-);
}
}
// 删除属性,并等待其他线程
pthread_attr_destroy(&attr);
for( i=; i < NUM_THREADS; i++ ){
rc = pthread_join(threads[i], &status);
if (rc){
cout << "Error:unable to join," << rc << endl;
exit(-);
}
cout << "Main: completed thread id :" << i ;
cout << " exiting with status :" << status << endl;
}
cout << "Main: program exiting." << endl;
pthread_exit(NULL);
}
当上面的代码被编译和执行时,它会产生下列结果:
main() : creating thread,
main() : creating thread,
main() : creating thread,
main() : creating thread,
main() : creating thread,
Sleeping in thread
Thread with id : ...exiting
Sleeping in thread
Thread with id : ...exiting
Sleeping in thread
Thread with id : ...exiting
Sleeping in thread
Thread with id : ...exiting
Sleeping in thread
Thread with id : ...exiting
Main: completed thread id : exiting with status :
Main: completed thread id : exiting with status :
Main: completed thread id : exiting with status :
Main: completed thread id : exiting with status :
Main: completed thread id : exiting with status :
Main: program exiting.
互斥锁的实现
互斥锁是实现线程同步的一种机制,只要在临界区前后对资源加锁就能阻塞其他进程的访问。
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
int sum = ; //定义全局变量,让所有线程同时写,这样就需要锁机制
pthread_mutex_t sum_mutex; //互斥锁
void* say_hello( void* args )
{
cout << "hello in thread " << *(( int * )args) << endl;
pthread_mutex_lock( &sum_mutex ); //先加锁,再修改sum的值,锁被占用就阻塞,直到拿到锁再修改sum;
cout << "before sum is " << sum << " in thread " << *( ( int* )args ) << endl;
sum += *( ( int* )args );
cout << "after sum is " << sum << " in thread " << *( ( int* )args ) << endl;
pthread_mutex_unlock( &sum_mutex ); //释放锁,供其他线程使用
pthread_exit( );
}
int main()
{
pthread_t tids[NUM_THREADS];
int indexes[NUM_THREADS];
pthread_attr_t attr; //线程属性结构体,创建线程时加入的参数
pthread_attr_init( &attr ); //初始化
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是设置你想要指定线程属性参数,这个参数表明这个线程是可以join连接的,join功能表示主程序可以等线程结束后再去做某事,实现了主程序和线程同步功能
pthread_mutex_init( &sum_mutex, NULL ); //对锁进行初始化
for( int i = ; i < NUM_THREADS; ++i )
{
indexes[i] = i;
int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) ); //5个进程同时去修改sum
if( ret != )
{
cout << "pthread_create error:error_code=" << ret << endl;
}
}
pthread_attr_destroy( &attr ); //释放内存
void *status;
for( int i = ; i < NUM_THREADS; ++i )
{
int ret = pthread_join( tids[i], &status ); //主程序join每个线程后取得每个线程的退出信息status
if( ret != )
{
cout << "pthread_join error:error_code=" << ret << endl;
}
}
cout << "finally sum is " << sum << endl;
pthread_mutex_destroy( &sum_mutex ); //注销锁
}
测试结果:
hello in thread hello in thread 1hello in thread hello in thread
before sum is in thread
hello in thread
after sum is in thread
before sum is in thread
after sum is in thread
before sum is in thread
after sum is in thread
before sum is in thread
after sum is in thread
before sum is in thread
after sum is in thread
finally sum is
可知,sum的访问和修改顺序是正常的,这就达到了多线程的目的了,但是线程的运行顺序是混乱的,混乱就是正常?
信号量的实现
信号量是线程同步的另一种实现机制,信号量的操作有signal
和wait
,本例子采用条件信号变量
pthread_cond_t tasks_cond;
信号量的实现也要给予锁机制。
#include <iostream>
#include <pthread.h>
#include <stdio.h>
using namespace std;
#define BOUNDARY 5
int tasks = ;
pthread_mutex_t tasks_mutex; //互斥锁
pthread_cond_t tasks_cond; //条件信号变量,处理两个线程间的条件关系,当task>5,hello2处理,反之hello1处理,直到task减为0
void* say_hello2( void* args )
{
pthread_t pid = pthread_self(); //获取当前线程id
cout << "[" << pid << "] hello in thread " << *( ( int* )args ) << endl;
bool is_signaled = false; //sign
while()
{
pthread_mutex_lock( &tasks_mutex ); //加锁
if( tasks > BOUNDARY )
{
cout << "[" << pid << "] take task: " << tasks << " in thread " << *( (int*)args ) << endl;
--tasks; //modify
}
else if( !is_signaled )
{
cout << "[" << pid << "] pthread_cond_signal in thread " << *( ( int* )args ) << endl;
pthread_cond_signal( &tasks_cond ); //signal:向hello1发送信号,表明已经>5
is_signaled = true; //表明信号已发送,退出此线程
}
pthread_mutex_unlock( &tasks_mutex ); //解锁
if( tasks == )
break;
}
}
void* say_hello1( void* args )
{
pthread_t pid = pthread_self(); //获取当前线程id
cout << "[" << pid << "] hello in thread " << *( ( int* )args ) << endl;
while()
{
pthread_mutex_lock( &tasks_mutex ); //加锁
if( tasks > BOUNDARY )
{
cout << "[" << pid << "] pthread_cond_signal in thread " << *( ( int* )args ) << endl;
pthread_cond_wait( &tasks_cond, &tasks_mutex ); //wait:等待信号量生效,接收到信号,向hello2发出信号,跳出wait,执行后续
}
else
{
cout << "[" << pid << "] take task: " << tasks << " in thread " << *( (int*)args ) << endl;
--tasks;
}
pthread_mutex_unlock( &tasks_mutex ); //解锁
if( tasks == )
break;
}
}
int main()
{
pthread_attr_t attr; //线程属性结构体,创建线程时加入的参数
pthread_attr_init( &attr ); //初始化
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是设置你想要指定线程属性参数,这个参数表明这个线程是可以join连接的,join功能表示主程序可以等线程结束后再去做某事,实现了主程序和线程同步功能
pthread_cond_init( &tasks_cond, NULL ); //初始化条件信号量
pthread_mutex_init( &tasks_mutex, NULL ); //初始化互斥量
pthread_t tid1, tid2; //保存两个线程id
int index1 = ;
int ret = pthread_create( &tid1, &attr, say_hello1, ( void* )&index1 );
if( ret != )
{
cout << "pthread_create error:error_code=" << ret << endl;
}
int index2 = ;
ret = pthread_create( &tid2, &attr, say_hello2, ( void* )&index2 );
if( ret != )
{
cout << "pthread_create error:error_code=" << ret << endl;
}
pthread_join( tid1, NULL ); //连接两个线程
pthread_join( tid2, NULL );
pthread_attr_destroy( &attr ); //释放内存
pthread_mutex_destroy( &tasks_mutex ); //注销锁
pthread_cond_destroy( &tasks_cond ); //正常退出
}
测试结果:
先在线程2中执行say_hello2,再跳转到线程1中执行say_hello1,直到tasks减到0为止。
[] hello in thread
[] pthread_cond_signal in thread
[] hello in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
[] pthread_cond_signal in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
[] take task: in thread
初学多线程 这个文章中间的线程参数传递存在问题 每一次运行存在参数中有int行的数据
程序就会boom boom boom
但是我不知道是为什么
希望各位大佬可以告诉我为什么 或者是你们电脑上面没有问题0.0
多线程的同步机制 所以有一些运行结果不是一样也不用在意 你多运行几次 说不定就有一次的运行结果和我的是一样的了
此文转+改,http://www.cnblogs.com/quincyhu/p/5884361.html