os:ubuntu   c++

1.创建线程

#include <iostream>

#include <pthread.h> //多线程相关操作头文件,可移植众多平台

using namespace std;

#define NUM_THREADS 5 //线程数

void* say_hello( void* args )

{

cout << "hello..." << endl;

} //函数返回的是函数指针,便于后面作为参数

int main()

{

pthread_t tids[NUM_THREADS]; //线程id

for( int i = 0; i < NUM_THREADS; ++i )

{

int ret = pthread_create( &tids[i], NULL, say_hello, NULL ); //参数:创建的线程id,线程参数,线程运行函数的起始地址,运行函数的参数

if( ret != 0 ) //创建线程成功返回0

{

cout << "pthread_create error:error_code=" << ret << endl;

}

}

pthread_exit( NULL ); //等待各个线程退出后,进程才结束,否则进程强制结束,线程处于未终止的状态

}

输入命令:g++ -o muti_thread_test_1 muti_thread_test_1.cpp -lpthread

注意:

1)此为c++程序,故用g++来编译生成可执行文件,并且要调用处理多线程操作相关的静态链接库文件pthread。

2)-lpthread 编译选项到位置可任意,如g++ -lpthread -o muti_thread_test_1 muti_thread_test_1.cpp

3)注意gcc和g++的区别,转到此文:点击打开链接

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_1

hello...hello...

hello...

hello...

hello...

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_1

hello...hello...hello...

hello...

hello...

可知,两次运行的结果会有差别,这不是多线程的特点吧?这显然没有同步?还有待进一步探索...

多线程的运行是混乱的,混乱就是正常?

2.线程调用到函数在一个类中,那必须将该函数声明为静态函数函数

因为静态成员函数属于静态全局区,线程可以共享这个区域,故可以各自调用。

[html] view plaincopy

#include <iostream>

#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

class Hello

{

public:

static void* say_hello( void* args )

{

cout << "hello..." << endl;

}

};

int main()

{

pthread_t tids[NUM_THREADS];

for( int i = 0; i < NUM_THREADS; ++i )

{

int ret = pthread_create( &tids[i], NULL, Hello::say_hello, NULL );

if( ret != 0 )

{

cout << "pthread_create error:error_code" << ret << endl;

}

}

pthread_exit( NULL );

}

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_2

hello...

hello...

hello...

hello...

hello...

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_2

hello...hello...hello...

hello...

hello...

3.如何在线程调用函数时传入参数呢?

先看下面修改的代码,传入线程编号作为参数:

[html] view plaincopy

#include <iostream>

#include <pthread.h> //多线程相关操作头文件,可移植众多平台

using namespace std;

#define NUM_THREADS 5 //线程数

void* say_hello( void* args )

{

int i = *( (int*)args ); //对传入的参数进行强制类型转换,由无类型指针转变为整形指针,再用*读取其指向到内容

cout << "hello in " << i <<  endl;

} //函数返回的是函数指针,便于后面作为参数

int main()

{

pthread_t tids[NUM_THREADS]; //线程id

cout << "hello in main.." << endl;

for( int i = 0; i < NUM_THREADS; ++i )

{

int ret = pthread_create( &tids[i], NULL, say_hello, (void*)&i ); //传入到参数必须强转为void*类型,即无类型指针,&i表示取i的地址,即指向i的指针

cout << "Current pthread id = " << tids[i] << endl; //用tids数组打印创建的进程id信息

if( ret != 0 ) //创建线程成功返回0

{

cout << "pthread_create error:error_code=" << ret << endl;

}

}

pthread_exit( NULL ); //等待各个线程退出后,进程才结束,否则进程强制结束,线程处于未终止的状态

}

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_3

hello in main..

Current pthread id = 3078458224

Current pthread id = 3070065520

hello in hello in 2

1

Current pthread id = hello in 2

3061672816

Current pthread id = 3053280112

hello in 4

Current pthread id = hello in 4

3044887408

显然不是想要的结果,调用顺序很乱,这是为什么呢?

这是因为多线程到缘故,主进程还没开始对i赋值,线程已经开始跑了...?

修改代码如下:

[html] view plaincopy

#include <iostream>

#include <pthread.h> //多线程相关操作头文件,可移植众多平台

using namespace std;

#define NUM_THREADS 5 //线程数

void* say_hello( void* args )

{

cout << "hello in thread " << *( (int *)args ) <<  endl;

} //函数返回的是函数指针,便于后面作为参数

int main()

{

pthread_t tids[NUM_THREADS]; //线程id

int indexes[NUM_THREADS]; //用来保存i的值避免被修改

for( int i = 0; i < NUM_THREADS; ++i )

{

indexes[i] = i;

int ret = pthread_create( &tids[i], NULL, say_hello, (void*)&(indexes[i]) );

if( ret != 0 ) //创建线程成功返回0

{

cout << "pthread_create error:error_code=" << ret << endl;

}

}

for( int i = 0; i < NUM_THREADS; ++i )

pthread_join( tids[i], NULL ); //pthread_join用来等待一个线程的结束,是一个线程阻塞的函数

}

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_3

hello in thread hello in thread hello in thread hello in thread hello in thread 30124

这是正常的吗?感觉还是有问题...待续

代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。

4.线程创建时属性参数的设置pthread_attr_t及join功能的使用

线程的属性由结构体pthread_attr_t进行管理。

typedef struct

{

int                           detachstate;     线程的分离状态

int                          schedpolicy;   线程调度策略

struct sched_param      schedparam;   线程的调度参数

int inheritsched; 线程的继承性

int scope; 线程的作用域

size_t guardsize; 线程栈末尾的警戒缓冲区大小

int stackaddr_set; void * stackaddr; 线程栈的位置

size_t stacksize; 线程栈的大小

}pthread_attr_t;

[html] view plaincopy

#include <iostream>

#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void* say_hello( void* args )

{

cout << "hello in thread " << *(( int * )args) << endl;

int status = 10 + *(( int * )args); //线程退出时添加退出的信息,status供主程序提取该线程的结束信息

pthread_exit( ( void* )status );

}

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功能表示主程序可以等线程结束后再去做某事,实现了主程序和线程同步功能

for( int i = 0; i < NUM_THREADS; ++i )

{

indexes[i] = i;

int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) );

if( ret != 0 )

{

cout << "pthread_create error:error_code=" << ret << 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;

}

}

}

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_4

hello in thread hello in thread hello in thread hello in thread 0hello in thread 321

4

pthread_join get status:10

pthread_join get status:11

pthread_join get status:12

pthread_join get status:13

pthread_join get status:14

5.互斥锁的实现

互斥锁是实现线程同步的一种机制,只要在临界区前后对资源加锁就能阻塞其他进程的访问。

[html] view plaincopy

#include <iostream>

#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

int sum = 0; //定义全局变量,让所有线程同时写,这样就需要锁机制

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( 0 );

}

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 = 0; i < NUM_THREADS; ++i )

{

indexes[i] = i;

int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) ); //5个进程同时去修改sum

if( ret != 0 )

{

cout << "pthread_create error:error_code=" << ret << 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;

}

}

cout << "finally sum is " << sum << endl;

pthread_mutex_destroy( &sum_mutex ); //注销锁

}

测试结果:

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_5

hello in thread hello in thread hello in thread 410

before sum is hello in thread 0 in thread 4

after sum is 4 in thread 4hello in thread

2

3

before sum is 4 in thread 1

after sum is 5 in thread 1

before sum is 5 in thread 0

after sum is 5 in thread 0

before sum is 5 in thread 2

after sum is 7 in thread 2

before sum is 7 in thread 3

after sum is 10 in thread 3

finally sum is 10

可知,sum的访问和修改顺序是正常的,这就达到了多线程的目的了,但是线程的运行顺序是混乱的,混乱就是正常?

6.信号量的实现

信号量是线程同步的另一种实现机制,信号量的操作有signal和wait,本例子采用条件信号变量pthread_cond_t tasks_cond;

信号量的实现也要给予锁机制。

[html] view plaincopy

#include <iostream>

#include <pthread.h>

#include <stdio.h>

using namespace std;

#define BOUNDARY 5

int tasks = 10;

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(1)

{

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 == 0 )

break;

}

}

void* say_hello1( void* args )

{

pthread_t pid = pthread_self(); //获取当前线程id

cout << "[" << pid << "] hello in thread " <<  *( ( int* )args ) << endl;

while(1)

{

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 == 0 )

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 = 1;

int ret = pthread_create( &tid1, &attr, say_hello1, ( void* )&index1 );

if( ret != 0 )

{

cout << "pthread_create error:error_code=" << ret << endl;

}

int index2 = 2;

ret = pthread_create( &tid2, &attr, say_hello2, ( void* )&index2 );

if( ret != 0 )

{

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为止。

[html] view plaincopy

wq@wq-desktop:~/coding/muti_thread$ ./muti_thread_test_6

[3069823856] hello in thread 2

[3078216560] hello in thread 1[3069823856] take task: 10 in thread 2

[3069823856] take task: 9 in thread 2

[3069823856] take task: 8 in thread 2

[3069823856] take task: 7 in thread 2

[3069823856] take task: 6 in thread 2

[3069823856] pthread_cond_signal in thread 2

[3078216560] take task: 5 in thread 1

[3078216560] take task: 4 in thread 1

[3078216560] take task: 3 in thread 1

[3078216560] take task: 2 in thread 1

[3078216560] take task: 1 in thread 1

到此,对多线程编程有了一个初步的了解,当然还有其他实现线程同步的机制,有待进一步探索

【整理】-- C++ 多线程的更多相关文章

  1. 笔记整理--Linux多线程

    Unix高级环境编程系列笔记 (2013/11/17 14:26:38) Unix高级环境编程系列笔记 出处信息 通过这篇文字,您将能够解答如下问题: 如何来标识一个线程? 如何创建一个新线程? 如何 ...

  2. 【Java】实验代码整理(多线程、自定义异常、界面)

    1.界面+文件输入输出流 package finalExam; import java.awt.BorderLayout; import java.awt.Container; import java ...

  3. Java多线程干货系列—(一)Java多线程基础

    前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的 ...

  4. iOS多线程中,队列和执行的排列组合结果分析

    本文是对以往学习的多线程中知识点的一个整理. 多线程中的队列有:串行队列,并发队列,全局队列,主队列. 执行的方法有:同步执行和异步执行.那么两两一组合会有哪些注意事项呢? 如果不是在董铂然博客园看到 ...

  5. Java多线程干货系列(1):Java多线程基础

    原文出处: 嘟嘟MD 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程 ...

  6. [转]Java多线程干货系列—(一)Java多线程基础

    Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...

  7. java 2018面试题-多线程汇总(含解答)

    学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行总结的,因此罗列了自己整理的多线程的问题,都是自己觉得比较经典和一些大企业面试会问 ...

  8. Java多线程干货系列—(二)synchronized

    原文地址:http://tengj.top/2016/05/03/threadsynchronized2/ <h1 id="前言"><a href="# ...

  9. 【JAVA】 04-Java中的多线程

    链接: 笔记目录:毕向东Java基础视频教程-笔记 GitHub库:JavaBXD33 目录: <> <> 内容待整理: 多线程引入 概述 多线程: 进程:正在执行中的程序,其 ...

  10. iOS开发之多线程(NSThread、NSOperation、GCD)

    整理一些多线程相关的知识. 并行 & 并发 1.并行:并行是相对于多核而言的,几个任务同时执行.2.并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是"同时" ...

随机推荐

  1. 10,SFDC 管理员篇 - 流程自动化

    1,Process Builder Setup | Build | Create | Workflow & Approvals | Process Builder 当我们在对象中创建或者修改一 ...

  2. 第五百八十二天 how can I 坚持

    好吧,是我错了,昨天,做好自己就行了,别人怎么样是别人的事,永远保持一颗单纯向上的心. 时间过得真快,明天又周六了.. 睡觉.

  3. centos6.5环境源码编译安装mysql5.6.34

    centos6.5环境源码编译安装mysql5.6.34 源码下载地址http://dev.mysql.com/downloads/mysql/5.6.html#downloads 选择Generic ...

  4. 借助 MySQLTuner 优化 MySQL 性能(转载的一篇文章)

    MySQLTuner 是一个 Perl 脚本,可以用来分析您的 MySQL 性能,并且基于收集到的信息给出相应的优化建议.这样子,您就可以调整 my.cnf 从而优化您的 MySQL 设置. 这边只是 ...

  5. 8天掌握EF的Code First开发系列之2 简单的CRUD操作

    本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 创建控制台项目 根据.Net中的类来创建数据库 简单的CRUD操作 数据库模式更改介绍 本章小结 本人的实验环境 ...

  6. 各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放 license收费等 ...

  7. 浅谈Eclipse寻找JVM(JRE)的顺序机制(转)

    转自:http://blog.csdn.net/teedry/article/details/6666850 Eclipse也是一个普通的Java程序,因此必须有一个JRE做为运行环境.        ...

  8. DrawerLayout学习,抽屉效果

    第一节: 注意事项 *主视图一定要是DrawerLayout的第一子视图 *主视图宽度和高度匹配父视图,因为当你显示主视图时,要铺满整个屏幕,用户体验度较高 *必须显示指定的抽屉视图的android: ...

  9. C#中dataGridView用法集

    SqlConnection conn = new SqlConnection('Server=(local);DataBase=test;User=sa;Pwd=sa'); SqlDataAdapte ...

  10. detection reading

    1512.07729v1 G-CNN an Iterative Grid Based Object Detector,先基于空间金字塔生成很多矩形框,然后把这些矩形框作为regions,进行fast ...