使用多线程的原因之一是,与进程相比,它是一种非常“节俭”的多任务操作模式. 我们知道,在Linux系统下,要启动一个新进程,必须将其分配给其独立的地址空间,建立大量数据表以维护其代码段,堆栈段和数据段,这是一种“昂贵的”多任务处理工作方式. 而且,多个线程在一个进程中运行,它们彼此使用相同的地址空间,共享大多数数据,启动线程所需的空间比启动进程所需的空间小得多,并且线程之间可以切换彼此所需的时间也远远少于在进程之间切换所需的时间. 据统计,一般来说,一个进程的成本大约是线程成本的30倍. 当然,在特定系统上,此数据可能会有很大的不同. 使用多线程的第二个原因是线程之间的便捷通信机制. 对于不同的进程,它们具有独立的数据空间,并且只能通过通信进行数据传输,这既费时又不方便. 线程不是这种情况. 由于数据空间是在同一进程中的线程之间共享的,因此一个线程的数据可以被其他线程直接使用linux用不了多线程,不仅快捷方便. 当然,数据共享还带来其他问题. 某些变量不能同时由两个线程修改. 一些子程序声明静态数据更有可能对多线程程序造成灾难性的打击. 这些积极的东西是编写多线程程序时要注意的最重要的事情. Linux系统下的多线程遵循POSIX线程接口,称为pthread. 要在Linux下编写多线程程序,需要使用头文件pthread.h,并且在连接时需要使用库libpthread.a. 以下给出了测试代码:
#include #include void线程(void){int i; for(i = 0; i <3; i ++)printf(“这是一个pthread. \ n”) ;} int main(void){pthread_t id; int i,ret; ret = pthread_create(&id,NULL,(void *)thread,NULL); if(ret!= 0){printf(“创建pthread错误!\ n “);返回-1;} for(i = 0; i <3; i ++)printf(”这是主进程. \ n“); pthread_join(id,NULL);返回(0);}
----------------------------- Makefile文件---------------- ----------------------------全部: multThread.ogcc -Wall -o main multThread.o -lpthreadPcapAvailable.o: gcc -Wall- c multThread.c -o multThread.oclean: rm -rf * .o main --------------------------------- -------------------------------------------------- ---------如果无法编译创建的C ++文件,请将void thread(void)的调用部分更改为void * thread(void *)到: ret = pthread_create(&id,NULL,thread,NULL) ;
第一次运行的结果: 〜/ Desktop / C / multThread $ ./main这是主进程这是主进程这是主进程这是pthread这是pthread这是一个pthread. 第二次运行结果: 〜/ Desktop / C / multThread $ ./main这是主进程. 这是主要过程. 这是一个pthread. 这是pthread. 这是pthread. 这是主进程. 前后两个的结果不同,这是两个线程争用CPU资源的结果. pthread_createpthread_t在头文件/usr/include/bits/pthreadtypes.h中定义,该文件是线程标识符. typedefunsigned long intpthread_t;函数pthread_create用于创建线程,其原型为: extern int pthread_create __P((pthread_t * __thread,__const pthread_attr_t * __ attr,void *(* __ start_routine)(void *),void * __ arg));一个参数是指向线程标识符的指针,第二个参数用于设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数.
在这里,我们的函数线程不需要参数,因此最后一个参数设置为空指针. 我们还将第二个参数设置为空指针,这将生成具有默认属性的线程. 成功创建线程后,该函数将返回0,新创建的线程将运行由参数3和参数4确定的函数,而原始线程将继续运行下一行代码. 如果不为0,则表示线程创建失败. 常见的错误返回代码为: EAGAIN表示系统限制了新线程的创建,例如,线程数太大; EINVAL表示第二个参数表示的线程属性值是非法的. pthread_join函数pthread_join用于等待线程结束. 函数原型是: extern int pthread_join __P((pthread_t __th,void ** __thread_return));第一个参数是要等待的线程的标识符,第二个参数是用户定义的指针,可用于存储等待的线程的返回值. 该功能是线程阻塞功能. 调用它的函数将等待,直到等待线程结束. 当函数返回时,将恢复等待线程的资源. 结束线程有两种方法. 一个是,就像上面的示例一样,函数结束,并且调用它的线程结束. 另一种方法是通过函数pthread_exit. 它的函数原型是: extern void pthread_exit __P((void * __ retval))__attribute__((__noreturn__));唯一的参数是该函数的返回码,只要pthread_join中的第二个参数thread_return不为NULL,则将传递该值给Give thread_return. 最后要注意的是,一个线程不能被多个线程等待,否则,接收信号的第一个线程将成功返回,而其余调用pthread_join的线程将返回错误代码ESRCH.
_____________________________ 2016.8.29更新__________________________________发现C ++ 11中支持线程. //线程示例#include // std :: cout#include // std :: thread#include void foo(){//做事... printf(“ foo执行!\ n“);} void bar(int x){//做一些事情... printf(” bar execute!\ n“);} int main(){std :: thread first(foo); //产生新的线程,该线程调用foo()std :: thread second(bar,0); //产生新的线程,调用bar(0)std :: cout
另一个例子: void publishPointCloud(int width,int height,ros :: Publisher&pub_cloud){......} std :: unique_ptr pointCloudThread = nullptr; // emptypointCloudThread.reset(new std :: thread(&publishPointCloud,width,height,std :: ref(pub_cloud))); // pointCloudThread获取newstd :: unique_ptr :: reset生成的指针的所有者------- ----------------------避免复位(指针p =指针())noexcept;重置指针销毁当前由unique_ptr管理的对象(如果有)并拥有p的所有权. 如果p是空指针(例如默认初始化的指针),则unique_ptr变为空,在调用之后不管理任何对象. 拥有存储指针的所有权而不破坏它,请使用成员函数release. 对运行时长度为(unique_ptr )的数组对象的unique_ptr特化不接受从element_type派生的类型的指针作为参数. 在这种情况下,将为空指针提供一个附加签名: public成员函数 std :: unique_ptr :: resetvoid重置(指针p =指针()). 重置指针销毁当前由unique_ptr管理的对象(如果有)并拥有p的所有权. 如果p是空指针(例如默认初始化的指针),则unique_ptr变为空,在调用之后不管理任何对象. 对存储的指针的所有权不破坏它,请改用成员函数release. 对于运行时长度为(unique_ptr )的数组对象,unique_ptr的特殊化不接受从element_type派生的类型的指针作为参数. 在这种情况下,为空指针提供了一个附加签名: pPointer,其所有权已由对象接管. 通常,该指针不应已经由任何其他托管指针管理(即,该值不应来自调用成员get托管指针).pointer是一种成员类型,定义为指向托管对象类型的指针类型. std :: mutex-- -------------类互斥锁;(自C + +11)互斥锁类是一个同步原语,可用于保护共享数据不被多个线程同时访问. 互斥锁提供专有的非递归所有权语义: 调用线程自成功调用其中一个后就拥有互斥锁锁定或try_lock,直到调用解锁. 当一个线程拥有一个互斥锁时,如果所有其他线程试图声明对该互斥锁的所有权,则所有其他线程都将阻塞(用于调用锁)或接收到错误的返回值(对于try_lock). 调用线程在调用锁之前一定不能拥有该互斥锁或try_lock. 如果一个互斥锁仍然由任何线程拥有时被销毁,或者一个线程在拥有一个互斥锁时终止,则程序的行为是不确定的. 互斥锁类满足Mutex和StandardLayoutType.std :: mutex的所有要求,它们既不可复制又不可移动.
OpenMP共享内存基础知识.
并行计算机可以简单地分为共享内存和分布式内存. 共享内存意味着多个内核共享一个内存,而当前的PC属于这种类型(无论是只有一个多核CPU还是可以插入多个CPU,它们都有多个内核和一个内存),一般的大型计算机将分布式内存与共享内存结构,即每个计算节点是共享内存,并且节点之间是分布式内存. 为了在这些并行计算机上获得更好的性能,并行编程是必要条件. 当前流行的并行编程方法是在分布式内存结构上使用MPI,在共享内存结构上使用Pthreads或OpenMP. 我们这里的重点是共享内存的并行计算机,因为编辑本文的计算机是这种类型的(普通台式机). 与Pthreads相比,OpenMP更简单. 对于那些只关注算法而只需要最基本地控制线程之间的关系(同步,互斥等)的人,OpenMP不再适用.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-254878-1.html