c++在windows下线程应该包含哪个头文件相互包含

酷勤网 C 程序员的那点事!
当前位置: >
浏览次数:次
读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。
现在Win32的API,用C++实现自己的读写锁。这组API包括:CreateMutex,CreateEvent,WaitForSingleObject,WaitForMultipleObjects,ResetEvent,ReleaseMutex,SetEvent,CloseHandle。以下代码在VS2005下,已经编译通过。
RWLockImpl.h
01.#ifndef _RWLockImpl_Header
02.#define _RWLockImpl_Header
04.#include
05.#include
06.#include
07.#include
12. 读写锁允许当前的多个读用户访问保护资源,但只允许一个写读者访问保护资源
15.//-----------------------------------------------------------------
16.class CRWLockImpl
18.protected:
19. CRWLockImpl();
20. ~CRWLockImpl();
21. void ReadLockImpl();
22. bool TryReadLockImpl();
23. void WriteLockImpl();
24. bool TryWriteLockImpl();
25. void UnlockImpl();
27.private:
28. void AddWriter();
29. void RemoveWriter();
30. DWORD TryReadLockOnce();
32. HANDLE m_
33. HANDLE m_readE
34. HANDLE m_writeE
35. unsigned m_
36. unsigned m_writersW
37. unsigned m_
40.//-----------------------------------------------------------------
42.class CMyRWLock: private CRWLockImpl
44.public:
46. //创建读/写锁
47. CMyRWLock(){};
49. //销毁读/写锁
50. ~CMyRWLock(){};
52. //获取读锁
53. //如果其它一个线程占有写锁,则当前线程必须等待写锁被释放,才能对保护资源进行访问
54. void ReadLock();
56. //尝试获取一个读锁
57. //如果获取成功,则立即返回true,否则当另一个线程占有写锁,则返回false
58. bool TryReadLock();
60. //获取写锁
61. //如果一个或更多线程占有读锁,则必须等待所有锁被释放
62. //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
63. void WriteLock();
65. //尝试获取一个写锁
66. //如果获取成功,则立即返回true,否则当一个或更多其它线程占有读锁,返回false
67. //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
68. bool TryWriteLock();
70. //释放一个读锁或写锁
71. void Unlock();
73.private:
74. CMyRWLock(const CMyRWLock&);
75. CMyRWLock& operator = (const CMyRWLock&);
78.inline void CMyRWLock::ReadLock()
80. ReadLockImpl();
83.inline bool CMyRWLock::TryReadLock()
85. return TryReadLockImpl();
88.inline void CMyRWLock::WriteLock()
90. WriteLockImpl();
93.inline bool CMyRWLock::TryWriteLock()
95. return TryWriteLockImpl();
98.inline void CMyRWLock::Unlock()
100. UnlockImpl();
104.#endif
RWLockImpl.cpp
01.#include &RWLockImpl.h&
03.CRWLockImpl::CRWLockImpl(): m_readers(0), m_writersWaiting(0), m_writers(0)
05. m_mutex = CreateMutex(NULL, FALSE, NULL);
06. if (m_mutex == NULL)
07. cout&&&cannot create reader/writer lock&&&
09. m_readEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
10. if (m_readEvent == NULL)
11. cout&&&cannot create reader/writer lock&&&
13. m_writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
14. if (m_writeEvent == NULL)
15. cout&&&cannot create reader/writer lock&&&
18.CRWLockImpl::~CRWLockImpl()
20. CloseHandle(m_mutex);
21. CloseHandle(m_readEvent);
22. CloseHandle(m_writeEvent);
25.inline void CRWLockImpl::AddWriter()
27. switch (WaitForSingleObject(m_mutex, INFINITE))
29. case WAIT_OBJECT_0:
30. if (++m_writersWaiting == 1)
31. ResetEvent(m_readEvent);
32. ReleaseMutex(m_mutex);
34. default:
35. cout&&&cannot lock reader/writer lock&&&
39.inline void CRWLockImpl::RemoveWriter()
41. switch (WaitForSingleObject(m_mutex, INFINITE))
43. case WAIT_OBJECT_0:
44. if (--m_writersWaiting == 0 && m_writers == 0)
45. SetEvent(m_readEvent);
46. ReleaseMutex(m_mutex);
48. default:
49. cout&&&cannot lock reader/writer lock&&&
53.void CRWLockImpl::ReadLockImpl()
55. HANDLE h[2];
56. h[0] = m_
57. h[1] = m_readE
58. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
60. case WAIT_OBJECT_0:
61. case WAIT_OBJECT_0 + 1:
63. ResetEvent(m_writeEvent);
64. ReleaseMutex(m_mutex);
65. assert(m_writers == 0);
67. default:
68. cout&&&cannot lock reader/writer lock&&&
72.bool CRWLockImpl::TryReadLockImpl()
74. for (;;)
76. if (m_writers != 0 || m_writersWaiting != 0)
79. DWORD result = TryReadLockOnce();
80. switch (result)
82. case WAIT_OBJECT_0:
83. case WAIT_OBJECT_0 + 1:
85. case WAIT_TIMEOUT:
87. default:
88. cout&&&cannot lock reader/writer lock&&&
93.void CRWLockImpl::WriteLockImpl()
95. AddWriter();
96. HANDLE h[2];
97. h[0] = m_
98. h[1] = m_writeE
99. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
101. case WAIT_OBJECT_0:
102. case WAIT_OBJECT_0 + 1:
103. --m_writersW
106. ResetEvent(m_readEvent);
107. ResetEvent(m_writeEvent);
108. ReleaseMutex(m_mutex);
109. assert(m_writers == 1);
111. default:
112. RemoveWriter();
113. cout&&&cannot lock reader/writer lock&&&
117.bool CRWLockImpl::TryWriteLockImpl()
119. AddWriter();
120. HANDLE h[2];
121. h[0] = m_
122. h[1] = m_writeE
123. switch (WaitForMultipleObjects(2, h, TRUE, 1))
125. case WAIT_OBJECT_0:
126. case WAIT_OBJECT_0 + 1:
127. --m_writersW
130. ResetEvent(m_readEvent);
131. ResetEvent(m_writeEvent);
132. ReleaseMutex(m_mutex);
133. assert(m_writers == 1);
135. case WAIT_TIMEOUT:
136. RemoveWriter();
137. default:
138. RemoveWriter();
139. cout&&&cannot lock reader/writer lock&&&
144.void CRWLockImpl::UnlockImpl()
146. switch (WaitForSingleObject(m_mutex, INFINITE))
148. case WAIT_OBJECT_0:
149. m_writers = 0;
150. if (m_writersWaiting == 0) SetEvent(m_readEvent);
151. if (--m_readers == 0) SetEvent(m_writeEvent);
152. ReleaseMutex(m_mutex);
154. default:
155. cout&&&cannot unlock reader/writer lock&&&
159.DWORD CRWLockImpl::TryReadLockOnce()
161. HANDLE h[2];
162. h[0] = m_
163. h[1] = m_readE
164. DWORD result = WaitForMultipleObjects(2, h, TRUE, 1);
165. switch (result)
167. case WAIT_OBJECT_0:
168. case WAIT_OBJECT_0 + 1:
170. ResetEvent(m_writeEvent);
171. ReleaseMutex(m_mutex);
172. assert(m_writers == 0);
174. case WAIT_TIMEOUT:
175. default:
176. cout&&&cannot lock reader/writer lock&&&
下边是测试代码
01.// MyRWLockWin32.cpp : 定义控制台应用程序的入口点。
04.#include &RWLockImpl.h&
06.//创建一个读写锁对象
07.CMyRWLock g_myRWL
08.volatile int g_counter = 0;
10.//线程函数
11.unsigned int __stdcall StartThread(void *pParam)
13. int lastCount = 0;
14. for (int i = 0; i & 10000; ++i)
16. g_myRWLock.ReadLock();
17. lastCount = g_
18. //在读锁域,两个线程不断循环交替访问全局变量g_counter
19. for (int k = 0; k & 100; ++k)
21. if (g_counter != lastCount)
22. cout&&&the value of g_counter has been updated.&&&
23. Sleep(0);
25. g_myRWLock.Unlock();
28. g_myRWLock.WriteLock();
29. //在写锁域,只有一个线程可以修改全局变量g_counter的值
30. for (int k = 0; k & 100; ++k)
33. Sleep(0);
35. for (int k = 0; k & 100; ++k)
38. Sleep(0);
41. if (g_counter &= lastCount)
42. cout&&&the value of g_counter is error.&&&
43. g_myRWLock.Unlock();
46. return (unsigned int)0;
49.int main(int argc, char* argv[])
51. HANDLE hThread1, hThread2;
52. unsigned int uiThreadId1, uiThreadId2;
54. //创建两个工作线程
55. hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId1);
56. hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId2);
58. //等待线程结束
59. DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
60. if ( dwRet == WAIT_TIMEOUT )
62. TerminateThread(hThread1,0);
64. dwRet = WaitForSingleObject(hThread2,INFINITE);
65. if ( dwRet == WAIT_TIMEOUT )
67. TerminateThread(hThread2,0);
70. //关闭线程句柄,释放资源
71. CloseHandle(hThread1);
72. CloseHandle(hThread2);
74. assert (g_counter == 20000);
76. system(&pause&);
77. return 0;
& 相关主题:
本文来源:c++在windows下线程应该包含哪个头文件_百度知道
c++在windows下线程应该包含哪个头文件
提问者采纳
#include&&Windows.h&//调用API函数创建线程HANDLE&Handle&=&CreateThread(NULL,&0,&Function,&parameters,&0,&NULL);&//参考博客:
其他类似问题
按默认排序
其他2条回答
标准C++11 include &thread&C&thread.h&应该其库比QTwxWidgets 两自线程类
直接用windows.h
头文件的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁C++windows下golang的go关键字功能实现
如何异步调用一个函数? aync ? thread ? NO!用Jojo,4个字符立马启动一个异步调用,资源占用小(话说怎么像路边买鞋子的
项目名:Jojo(job 和joker的缩写 ,不要和JoJo的奇妙冒险搞混了)
Ver:0.1 debug
开源项目,详见源代码包内
支持平台:windows8,windows8.1
支持编译器:vs2013,vs2012
库依赖:boost.interrprocessor(愿意的话可以自己替换成windows的) boost.thread,boost.thread.tss
语言:C++
编译方式:打开go文件夹下的vs2013工程文件,然后编译为静态库,最后包含头文件和库目录即可
简介:golang中go关键字功能在C++下的实现,暂时没有实现用户级线程抢占,只能靠用户自己yield
(欢迎喷,提交bug,正面上我啊!顺带求大牛告知怎么才能实现
windows下用户态的Fiber抢占切换..Golang竟然用编译器作弊)
1:如何启动一个task
#include &go/go.h&
#include &windows.h&
#include &iostream&
int main()
(这里可以写任意C++代码,参数默认从外部引用(其实就是C++lambda中的&的效果)
&cout&&&start task&&&
Sleep(100);//防止输出前退出程序
}你也可以使用如下代码对外部的参数进行复制传参(扩展语法与C++lamdbda一样)
2:如何task间通信?
#include &go/go.h&
#include &channel/channel.h&
#include &iostream&
int main()
isu::channel&int&(不用担心析构问题,channel与shared_ptr有一样的特性)
int val=1;
int val=0;
c&&(阻塞的,直到有数据被放入C)
std::cout&&val&&std::
}任何windows内核对象也可以用作task的同步
3:如何释放task时间片?
包含&go/gohelper.h& 然后在函数代码块中使用isu::go::yield()函数即可
4:效率和资源占用问题
暂时没有好的程序来测试,尝试了一下单线程下对list&int&插入4千万个int,jo版本要比单线程快10%,但是代码多了20行
Jo内部对于task的创建资源消耗不多(一个CONTEXT,一个SEH,一个Data,一个栈,一共200字节),
起码比线程要少,而且创建的要快,但是不支持分段栈(GCC下可以支持,还没写.)
task最高的栈可以有1MB
5:我该用它吗?
如果你会用ppl或者一些工业级并行库,切不嫌麻烦的话。还是不要用Jo的好..
6:某些问题
由于没有实现用户级的task抢占调度(其实就是操作系统对线程的调用变成对task的)
所以不要在一个task用死循环。。如果一定要用的话在必要的时刻请使用isu::go::yield,
否则将无法处理其他的任务
7:我同时可以运行多少个task?
3000个左右(和内核有关),创建task的数量不限制,只要你内存扛得住
8:Jo会使用多少线程,我可以设置他吗?
默认情况下是你的CPU核心数+1(调度线程),你可以用过gohelper.h中的max_processor来设置
上一篇:掀桌,windows下的分段栈至少还是要分配一个页面
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
iOS Android
移动游戏 Windows Phone
Hadoop OpenStack
MySQL textview
可穿戴计算
XAML ASP.NET 前端开发
低防boost程序库(3)
脑洞产物(5)
Windows核心编程勘误(0)
支持全正则表达式的类似于ssanf_s的类-----------cssanf(142)
cscanf---关于异常的抛出(126)
关于cscanf如何替换正则引擎的问题(89)
如何让cscanf支持中文,超简单(89)
用interlocked提醒线程任务结束(43)
参数复制到目标栈(16)
如何获取Fiber的CONTEXT(13)
(责任编辑:赵红霞)
------分隔线----------------------------
# -*- encoding: utf-8 -*-import urllibimport urllib2from urllib import urlencodei...
Top 20+ Java Developers’ BlogsThis topic has been in my mind for a very long ti...
问题描述一开始开始机器为Win7环境,使用的是域用户user.group(...
宫粉雕痕...
前言: FileUpload 服务器控件用多了,自己写html控件通过表单上传...
最近有点想写博客的冲动,不为别的,只为能为那些和我一样碰...当前位置:&&
& & &TCMalloc (google-perftools) 是用于优化C++写的多线程应用,比glibc 2.3的malloc快。这个模块可以用来让MySQL在高并发下内存占用更加稳定。tcmalloc下载地址: & tcmalloc下载当前最新版为: gperftools-2.1.tar.gz, &gperftools-2.1.ziptcmalloc安装方法#tar&zxvf&libunwind-0.98.6.tar.gz
#cd&libunwind-0.98.
& &C++ Iterator迭代器介绍&& &迭代器可被用来访问一个容器类的所包函的全部元素,其行为像一个指针。举一个例子,你可用一个迭代器来实现对vector容器中所含元素的遍历。有这么几种迭代器如下:迭代器 描述&input_iterator 提供读功能的向前移动迭代器,它们可被进行增加(++
&& Vectors 包含着一系列连续存储的元素,其行为和数组类似。访问Vector中的任意元素或从末尾添加元素都可以在常量级时间复杂度内完成,而查找特定值的元素所处的位置或是在Vector中插入元素则是线性时间复杂度。& &c++ stl容器vector的头文件为: &#include &vector&& &c++ stl
c++ stl栈stack介绍C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。c++ stl栈stack的头文件为:&#include &stack&&c++ stl栈stack的成员函数介绍操作 比较和分配堆栈empty() 堆栈为空则返回真pop() 移除栈顶元素push() 在栈
&c++ stl集合set介绍& &c++ stl集合(Set)是一种包含已排序对象的关联容器。set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。1) 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素2) 不
& & Boost库是一个经过千锤百炼、可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起,在C++社区中影响甚大,其成员已近2000人。 Boost库为我们带来了最新、最酷、最实用的技术,是不折不扣的“准”标准库。本站主要
& & C++队列queue模板类的定义在&queue&头文件中,queue 模板类需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。& & C++队列Queue是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。C++队列Queue类成员函数如下
&& & C++ STL库中priority_queue介绍& &C++优先队列priority_queue类似队列, 但是在这个数据结构中的元素按照一定的断言排列有序。& &优先级队列priority_queue顾名思义是根据元素的优先级被读取,接口和queues非常相近。程序员可以通过template参数指定一个排序准则。缺省的排序准
&动态断言(assert) & assert宏的原型定义在& assert.h&中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:#include & assert.h&
void assert( int expression ); & C++ assert()函数的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后
windows下tinyxml.dll下载安装使用(c++解析XML库) & &TinyXML是解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。- & &Analytical Analysis of XML libraries, can be used to C++, Can be compiled in Windows
&TinyXML是一个优秀的C++ XML解析器。TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。DOM模型即文档对象模型,是将整个文档分成多个元素(如书、章、节、段等)
ticpp(TinyXML++)TinyXML的C++封装介绍 & &ticpp(TinyXML++)正式名称为ticpp,ticpp是一个使用c++语言封装的全新的基于TinyXML的操作XML的库。它使用了模板,异常和错误处理。 & &ticpp(TinyXML++) is a completely new interface to TinyXML that uses MANY of the C++ strengths. Templates, exceptions, and much better error handling.It is r
C++ STL MultiSet类成员函数介绍及具体用法示例1、C++ STL MultiSet 简介 & & C++ STL MultiSet跟set具有相同功能,但允许重复的元素。multiset容器的内部结构通常由平衡二叉树(balanced binary tree)来实现。当元素放入容器中时,会按照一定的排序法则自动排序,默认是按照less&&排序规则来排序。这种
& &c++ stl multimap基本操作使用技巧详细介绍C++ stl &Multimap 和C++ stl &map 很相似,但是MultiMap允许重复的元素。C++ stl &Multimap的基本操作类成员函数列表介绍如下:begin()返回指向第一个元素的迭代器clear()删除所有元素count()返回一个元素出现的次数empty()如果multimap为空则返回真end()返
C++可变参数模板(variadic template)详细介绍及代码举例 C++11 语言核心的改进中,最为关注的有 rvalue reference,lambda,variadic template。rvalue 规则稍微复杂,但一旦理解和记住了,应用上就没有什么困难。lambda 其实是一个“很自然”的语言设施,除了语法稍显诡异之外,习惯了就能马上用上,而且是能
Linux下c/c++ boost安装过程: 1.下载boost1.53源文件http://sourceforge.net/projects/boost/files/latest/download?source=dlp 2.解压后,进入boost_1_53_0目录,执行:./bootstrap.sh 3.(重点)修改 &tools/build/v2/user-config.jam文件,在最后面加上一行“”(注意mpi后面有个空格, & & & 然后一个分号 ) 4. 执行: ./b2
& & c++的boost库多线程(Thread)编程(线程操作,互斥体mutex,条件变量)详解 & & Boost是由C++标准委员会类库工作组成员发起,致力于为C++开发新的类库的组织。许多C++专家都投身于Boost线程库的开发中。所有接口的设计都是从0开始的,并不是C线程API的简单封装。许多C++特性(比如构造函
& Linux下gettimeofday()函数和clock()函数:精确到毫秒级的时间 & 使用Linux的gettimeofday函数可以达到获取精确到毫秒级的时间,其中t1=t_start.tv_sec是公元1970年至今的时间(换算为秒),t2=t_start.tv_usec是当前秒数下的微秒,所以将t1*0可以得到当前的毫秒数。 & gettimeofday()函数原型及相关
&C++ Maps是一种关联式容器,包含“关键字/值”对,头文件:#include &&map&,其成员函数列表如下:begin()返回指向map头部的迭代器clear()删除所有元素count()返回指定元素出现的次数empty()如果map为空则返回trueend()返回指向map末尾的迭代器equal_range()返回特殊条目的迭代器对erase()删除一个元素fin
& & c++ STL List将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢.c++ STL List就是一双向链表,可高效地进行插入删除元素。包括构造、方法等。 & & c++ STL List构造方法:list&int& c0; //空链表list&int& c1(3); //建一个含三个默认值是0
&C++ Double Ended Queues(双向队列)成员函数列表参考 &双向队列和向量很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样)。 & &Deque成员函数如下:Constructors创建一个新双向队列Operators比较和赋值双向队列assign()设置双向队列的值at()返回指定的元素back()返回最后一个元素b
&Linux下c/c++开发之程序崩溃(Segment fault)时内核转储文件(core dump)生成设置方法 &Linux下c/c++开发程序崩溃(Segment fault)通常都是指针错误引起的.以下是我们详细的对Linux core dump的调试技术进行的介绍:
Linux core dump简介有的程序可以通过编译, 但在运行时会出现Segment fault(段错误). 这通常都是指
& & STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。在C++标准中,STL被组织为下面的13个头文件:&algorithm&、&deque&、&
C++ STL Bitsets构造函数及成员函数解释及代码示例C++ Bitsets给程序员提供一种位集合的数据结构。Bitsets使用许多二元操作符,比如逻辑和,或等。C++ STL &Bitsets 构造函数 Constructors:创建新bitsetsC++ STL &Bitsets 操作符 & Operators:比较和赋值bitsetsC++ STL &Bitsets 成员函数 any():如果有任何一
c/c++ 常用转义字符以下的转义字符使普通字符表示不同的意义.转义字符 & 描述\' & & & &单引号\& & & & &双引号\\ & & & &反斜杠\0 & & & &空字符\a & & & &响铃\b & & & &后退\f & & & &走纸\n &
c/c++ 操作符优先级参考表优先级
& 操作符1 & & & &() [] -& &. & :: &2 & & & & ! ~ ++ -- &- (unary)* (dereference) & (address of) &sizeof3 & & & & -&* & &.*4 & & & & * (multiply) & / & %5 & & & & + & &-6 &nb
c/c++预处理命令之预定义变量预定义变量语法: &__LINE__ &__FILE__ &__DATE__ &__TIME__ &_cplusplus &__STDC__下列参数在不同的编译器可能会有所不同, 但是一般是可用的:__LINE__ 和 __FILE__ 变量表示正在处理的当前行和当前文件.__DATE__ 变量表示当前日期,格式为month/day/year(月/日/年).__TIME__ 变
c/c++预处理命令预#undef介绍#undef#undef命令取消一个先前已定义的宏变量, 譬如一个用#define定义的变量.
c/c++预处理命令预#pragma介绍#pragma & #pragma命令可以让编程者让编译器执行某些事. 因为#pragma命令的执行很特殊,不同的编译器使用有所不同. 一个选项可以跟踪程序的执行.
c/c++预处理命令预#line介绍#line语法: &#line line_number &filename&#line命令是用于更改__LINE__ 和 __FILE__变量的值. 文件名是可选的. __LINE__ 和 __FILE__ 变量描述被读取的当前文件和行. 命令 & &#line 10 &main.cpp&更改行号为10,当前文件改为&main.cpp&.
&1&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!
(C)2012-,站长邮箱:www_169it_(请将#改为@)您现在的位置:&&>>&&>>&&>>&&>>&正文
C++多线程,消息队列用法
  进程是没有活力的,它只是一个静态的概念。为了让进程完成一些工作,进程必须至少占有一个线程,所以线程是描述进程内的执行,正是线程负责执行包含在进程的地址空间中的代码。实际上,单个进程可以包含几个线程, 它们可以同时执行进程的地址空间中的代码。为了做到这一点,每个线程有自己的一组CPU寄存器和堆栈。
  线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给系统。主执行线程终止了,进程也就随之终止。
  每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。
  多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。
  现代操作系统大都提供了相应的机制,用来处理线程的生存期、同步,以及其他“和线程有关”的属性,如优先级、线程专有空间(thread-specific storage)等。多线程编程是一门语言的难点和重点。
  接下来让我们看看处理线程的函数:pthread_create()函数,创建线程函数原型如下:int pthread_create(pthread_t *restrict thread,const pthread_attr_t *restrict attr,void *(*start_routine)(void*), void *restrict arg);参数讲解:1、每个线程都有自己的ID即thread ID,可以简称tid,呵呵,是不是想起什么来了?……对,和pid有点象。其类型为pthread_t,pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedef unsigned long int pthread_t;可以看成是线程的标志符。当成功创建一个新线程的时候,系统会为该线程分配一个tid,并将该值通过指针返回给调用它的程序。
  2、attr申明线程的属性。
  属性结构为pthread_attr_t,它在头文件/usr/include/pthread.h中定义。设为NULL,表示在这里我们只使用线程的默认属性就可以了。
  3、start_routine表示新创建的线程所要执行的例程。线程以调用该函数开始,直到由该函数返回(return)终止这个线程,或者在start_routine所指向的函数中调用pthread_exit函数终止。start_routine只有一个参数,该参数由随后的arg指针来指出。
  4、arg:也是一个指针,也就是start_routine指针所指向的函数的参数。
  返回值:当pthread_create调用成功时,该调用返回0;否则,返回一个错误代码指出错误的类型。
  pthread_exit()函数线程的终止可以是调用了pthread_exit或者该线程的例程结束。也就是说,一个线程可以隐式的退出,也可以显式的调用pthread_exit函数来退出。
  函数原型如下:void pthread_exit( void * value_ptr );线程的终止可以是调用了pthread_exit或者该线程的例程结束。也就是说,一个线程可以隐式的退出,也可以显式的调用pthread_exit函数来退出pthread_exit函数唯一的参数value_ptr是函数的返回代码,只要pthread_join中的第二个参数value_ptr不是NULL,这个值将被传递给value_ptr pthread_join()函数,等待一个线程终止调用pthread_join的线程将被挂起直到参数thread所代表的线程终止时为止。pthread_join是一个线程阻塞函数,调用它的函数将一直等到被等待的线程结束为止。
  函数原型如下:int pthread_join(pthread_t th, void **thread_return);如果value_ptr不为NULL,那么线程thread的返回值在该指针指向的位置。该返回值可以是由pthread_exit给出的值,或者该线程被取消而返回PTHREAD_CANCELED.当一个非分离的线程终止后,该线程的内存资源(线程描述符和栈)并不会被释放,直到有线程对它使用了pthread_join时才被释放。因此,必须对每个创建为非分离的线程调用一次pthread_join调用,以避免内存泄漏。否则当线程是可分离的,调用pthread_exit,将终止该调用线程,并释放所有资源,没有线程等待它终止。
  至多只能有一个线程等待给定的线程终止。如果已经有一个线程在等待thread线程终止了,那么再次调用pthread_join等待同一线程的线程将返回一个错误
  下多线程的实现方法:1)使用全局变量& 2)不使用全局变量&& 3)线程相关的数据实例1 #include &string.h& #include &pthread.h& #include &stdio.h&
  #define MAXLENGTH 20
  void another_func(const char* threadName)
  { printf("%s is running in another_func\n",threadName);}
  void * thread_func(void *args)
  { char threadName[MAXLENGTH];strncpy(threadName,(char*)args,MAXLENGTH-1);
  printf("%s is running in thread_func\n",threadName);another_func(threadName);}
  int main(int argc,char* argv[])
  { pthread_t pa,pb;pthread_create(&pa, NULL, thread_func, "Thread A");pthread_create(&pb, NULL, thread_func, "Thread B");
  pthread_join(pa, NULL);pthread_join(pb, NULL);return 0;}输出结果为:Thread A is running in thread_func Thread A is running in another_func Thread B is running in thread_func Thread B is running in another_func
  该方法的缺点是:由于要记录是哪一个线程在调用函数,每个函数需要一个额外的参数来记录线程的名字,例如another_func函数需要一个threadName参数如果调用的函数多了,则每一个都需要一个这样的参数
  实例2 #include &string.h& #include &pthread.h& #define MAXLENGTH 20
  char threadName[MAXLENGTH];pthread_mutex_t sharedMutex=PTHREAD_MUTEX_INITIALIZER;
  void another_func ()
  { printf ("%s is running in another_func\n", threadName);}
  void * thread_func (void * args)
  { pthread_mutex_lock(&sharedMutex);strncpy (threadName, (char *)args, MAXLENGTH-1);printf ("%s is running in thread_func\n", threadName);another_func ();pthread_mutex_unlock(&sharedMutex);
  int main (int argc, char * argv[])
  pthread_t pa, pb;pthread_create ( &pa, NULL, thread_func, "Thread A");pthread_create ( &pb, NULL, thread_func, "Thread B");
  pthread_join (pa, NULL);pthread_join (pb, NULL);}该方法的缺点是:由于多个线程需要读写全局变量threadName,就需要使用互斥机制
  分析以上两种实现方法,Thread-Specific Data "线程相关的数据"的一个好处就体现出来了:(1)"线程相关的数据"可以是一个全局变量,并且(2)每个线程存取的"线程相关的数据"是相互独立的。
  实例3 #include &string.h& #include &pthread.h&
  pthread_key_t p_key;
  void another_func ()
  { printf ("%s is running in another_func\n", (char *)pthread_getspecific(p_key));}
  void * thread_func (void * args)
  { pthread_setspecific(p_key, args);printf ("%s is running in thread_func\n", (char *)pthread_getspecific(p_key));another_func ();
  int main (int argc, char * argv[])
  pthread_t pa, pb;
  pthread_key_create(&p_key, NULL);
  pthread_create ( &pa, NULL, thread_func, "Thread A");pthread_create ( &pb, NULL, thread_func, "Thread B");
  pthread_join (pa, NULL);pthread_join (pb, NULL);}
  线程互斥
  互斥操作,就是对某段代码或某个变量修改的时候只能有一个线程在执行这段代码,其他线程不能同时进入这段代码或同时修改该变量。这个代码或变量称为临界资源。
  例如:有两个线程A和B,临界资源为X,首先线程A进入,将X置为加锁状态,在A将锁打开之前的这段时间里,如果此时恰巧线程B也欲获得X,但它发现X处于加锁状态,说明有其它线程正在执行互斥部分,于是,线程B将自身阻塞……线程A处理完毕,在退出前,将X解锁,并将其它线程唤醒,于是线程B开始对X进行加锁操作了。通过这种方式,实现了两个不同线程的交替操作。
  一个互斥体永远不可能同时属于两个线程。或者处于锁定状态;或者空闲中,不属于任何一个线程。
  实例1 #include &stdio.h& #include &pthread.h&
  void * pthread_func_test(void * arg);
  pthread_mutex_t mu;
  int main()
  { int i;pthread_t pt;
  pthread_mutex_init(&mu,NULL); //声明mu使用默认属性,此行可以不写pthread_create(&pt,NULL,pthread_func_test,NULL);for(i = 0; i & 3; i++)
  { pthread_mutex_lock(&mu);printf("主线程ID是:%lu ",pthread_self()); //pthread_self函数作用:获得当前线程的id pthread_mutex_unlock(&mu);sleep(1);}
  void * pthread_func_test(void * arg)
  { int j;for(j = 0; j & 3; j++)
  { pthread_mutex_lock(&mu);printf("新线程ID是:%lu ",pthread_self());pthread_mutex_unlock(&mu);sleep(1);}终端输出结果:
  主线程ID是 : 新线程ID是 :
  主线程ID是 : 新线程ID是 :
  主线程ID是 : 新线程ID是 :
  pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,都处于加锁状态中,即同一时间只能被一个线程调用执行。当另一个线程执行到pthread_mutex_lock处时,如果该锁此时被其它线程使用,那么该线程被阻塞,即程序将等待到其它线程释放此互斥锁。
  pthread_mutex_init()函数& 作用:初始化互斥体类型变量mutex,变量的属性由attr进行指定。attr设为NULL,即采用默认属性,这种方式与pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER的方式等价。
  函数原型如下:int pthread_mutex_lock(pthread_mutex_t *mutex);
  pthread_mutex_unlock()函数& 作用:如果当前的线程拥有参数mutex所指定的互斥体,那么该函数调用将该互斥体解锁。
  函数原型如下:int pthread_mutex_unlock(pthread_mutex_t *mutex);pthread_mutex_destroy()函数& 作用:用来释放互斥体所占用的资源。
  函数原型如下:int pthread_mutex_destroy(pthread_mutex_t *mutex);pthread_self()函数& 作用:获得线程自身的ID.前面我们已经提到过,pthread_t的类型为unsigned long int,所以在打印的时候要使用%lu方式,否则将产生奇怪的结果。
  函数原型如下:pthread_t pthread_self(void);但是上面的代码并不完善,假设将循环次数修改得足够的长,打印后的结果可能并不是我们所希望看到的交替打印,可能象下面这样:主线程ID是 : 新线程ID是 :
  主线程ID是 : 新线程ID是 :
  新线程ID是 : 主线程ID是 :
  这是什么原因呢?因为Linux是分时操作系统,采用的是时间片轮转的方式,主线程和新线程可能因为其它因素的干扰,获得了非顺序的时间片。如果想要严格的做到“交替”方式,可以略施小计,即加入一个标志。
  实例1 #include &stdio.h& #include &pthread.h&
  void * pthread_func_test(void * arg);
  pthread_mutex_t mu;int flag = 0;
  int main()
  { int i;pthread_t pt;
  pthread_mutex_init(&mu,NULL);pthread_create(&pt,NULL,pthread_func_test,NULL);for(i = 0; i & 3; i++)
  { pthread_mutex_lock(&mu);if(flag == 0)
  printf("主线程ID是:%lu ",pthread_self());flag = 1;pthread_mutex_unlock(&mu);sleep(1);} pthread_join(pt, NULL);pthread_mutex_destroy(&mu);}
  void * pthread_func_test(void * arg)
  { int j;for(j = 0; j & 3; j++)
  { pthread_mutex_lock(&mu);if(flag == 1)
  printf("新线程ID是:%lu ",pthread_self());flag == 0;pthread_mutex_unlock(&mu);sleep(1);}在使用互斥锁的过程中很有可能会出现死锁:即两个线程试图同时占用两个资源,并按不同的次序锁定相应的互斥锁,例如两个线程都需要锁定互斥锁1和互斥锁2,A线程先锁定互斥锁1,B线程先锁定互斥锁2,这时就出现了死锁。此时我们可以使用函数pthread_mutex_trylock,该函数企图锁住一个互斥体,但不阻塞pthread_mutex_trylock()函数 作用:函数thread_mutex_trylock()用来锁住参数mutex所指定的互斥体。如果参数mutex所指的互斥体已经被上锁,该调用不会阻塞等待互斥体的解锁,而会返回一个错误代码。通过对返回代码的判断,程序员就可以针对死锁做出相应的处理。所以在对多个互斥体编程中,尤其要注意这一点。
  函数原型如下:int pthread_mutex_trylock(pthread_mutex_t *mutex);线程同步
  首先来看一下有关同步机制的概念。同步就是若干个线程等待某个事件的发生,当等待事件发生时,一起开始继续执行。可以这样简单理解同步,就是若干个线程各自对自己的数据进行处理,然后在某个点必须汇总一下数据,否则不能进行下一步的处理工作。
  线程同步的函数调用有pthread_cond_init、pthread_cond_broadcast、pthread_cond_signal、pthread_cond_wait和pthread_cond_destroy
  pthread_cond_init()函数& 函数说明:按attr指定的属性初始化cond条件变量。如果attr为NULL,效果等同于pthread_cond_t cond = PTHREAD_COND_INITIALIZER函数原型如下:int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);pthread_cond_broadcast()函数 函数说明:对所有等待cond这个条件变量的线程解除阻塞。
  函数原型如下:int pthread_cond_broadcast(pthread_cond_t *cond);pthread_cond_signal()函数& 函数说明:仅仅解除等待cond这个条件变量的某一个线程的阻塞状态。如果有若干线程挂起等待该条件变量,该调用只唤起一个线程,被唤起的线程是哪一个是不确定的。
  函数原型如下:int pthread_cond_signal(pthread_cond_t *cond);pthread_cond_wait()函数 函数说明:该调用自动阻塞发出调用的当前线程,并等待由参数cond指定的条件变量,而且为参数mutex指定的互斥体解锁。被阻塞线程直到有其他线程调用pthread_cond_signal或pthread_cond_broadcast函数置相应的条件变量时,而且获得mutex互斥体才解除阻塞。等待状态下的线程不占用CPU时间。
  函数原型如下:int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);pthread_cond_timedwait()函数& 函数说明:该函数自动阻塞当前线程等待参数cond指定的条件变量,并为参数mutex指定的互斥体解锁。被阻塞的线程被唤起继续执行的条件是:有其他线程对条件变量cond调用pthread_cond_signal函数;或有其他线程对条件变量cond调用pthread_cond_broadcast;或系统时间到达abstime参数指定的时间;除了前面三个条件中要有一个被满足外,还要求该线程获得参数mutex指定的互斥体。
  函数原型如下:int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);pthread_cond_destroy()函数 函数说明:释放cond条件变量占用的资源。
  函数原型如下:int pthread_cond_destroy(pthread_cond_t *cond);#include &stdio.h& #include &pthread.h&
  pthread_t pt1,pt2;pthread_mutex_t mu;pthread_cond_t cond;int i = 1;
  void * decrease(void * arg)
  { while(1)
  { pthread_mutex_lock(&mu);if(++i)
  { printf("%d ",i);if(i != 1) printf("Error ");pthread_cond_broadcast(&cond);pthread_cond_wait(&cond,&mu);} sleep(1);pthread_mutex_unlock(&mu);}
  void * increase(void * arg)
  { while(1)
  { pthread_mutex_lock(&mu);if(i――)
  { printf("%d ",i);if(i != 0) printf("Error ");pthread_cond_broadcast(&cond);pthread_cond_wait(&cond,&mu);} sleep(1);pthread_mutex_unlock(&mu);}
  int main()
  { pthread_create(&pt2,NULL,increase,NULL);pthread_create(&pt1,NULL,decrease,NULL);pthread_join(pt1,NULL);pthread_join(pt2,NULL);}
【责编:eric】
?&[]?&[]?&[]?&[]?&[]?&[]?&[]?&[]?&[]?&[]
相关产品和培训
 友情推荐链接
 认证培训
 专题推荐
 ? ? ? ? ? ? ? ? ? ?
 今日更新
?&?&?&?&?&?&?&?&?&?&
 社区讨论
 博客论点
 频道精选
 C/C++频道相关导航

我要回帖

更多关于 红头文件模板 的文章

 

随机推荐