-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
182 lines (170 loc) · 9.63 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://ZypherChan.github.io</id>
<title>Zypher</title>
<updated>2019-07-09T13:10:07.724Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<link rel="alternate" href="https://ZypherChan.github.io"/>
<link rel="self" href="https://ZypherChan.github.io/atom.xml"/>
<subtitle>Remember that 1.01^365=37.7834</subtitle>
<logo>https://ZypherChan.github.io/images/avatar.png</logo>
<icon>https://ZypherChan.github.io/favicon.ico</icon>
<rights>All rights reserved 2019, Zypher</rights>
<entry>
<title type="html"><![CDATA[GuiLite(轻量级GUI库)]]></title>
<id>https://ZypherChan.github.io/post/guiliteqing-liang-ji-gui-ku</id>
<link href="https://ZypherChan.github.io/post/guiliteqing-liang-ji-gui-ku">
</link>
<updated>2019-07-09T13:03:55.000Z</updated>
<content type="html"><![CDATA[<h1 id="guilite">GuiLite</h1>
<p>最近发现了一个很轻量的GUI库GuiLite,代码总共5000行。这个GUI库的思想是基于DirectUI的思想,本身没有绘图功能只是提供了绘图框架,看起来很小巧。很适合我这种对GUI感兴趣的开发者,我们可以通过阅读源码来提高本身对GUI框架的理解。下面该库的整体结构:</p>
<h1 id="类图">类图</h1>
<p><img src="https://ZypherChan.github.io/post-images/1562677656493.png" alt=""></p>
<h1 id="ui交互">UI交互</h1>
<p><img src="https://ZypherChan.github.io/post-images/1562677665560.png" alt=""></p>
<p>项目地址:<a href="https://github.com/idea4good/GuiLite">https://github.com/idea4good/GuiLite</a></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[CreateThread与_beginthreadex本质区别]]></title>
<id>https://ZypherChan.github.io/post/createthread-yu-_beginthreadex-ben-zhi-qu-bie</id>
<link href="https://ZypherChan.github.io/post/createthread-yu-_beginthreadex-ben-zhi-qu-bie">
</link>
<updated>2019-07-01T14:41:29.000Z</updated>
<content type="html"><![CDATA[<p>第一个 CreateThread</p>
<p>函数功能:创建线程</p>
<p>函数原型:</p>
<p>HANDLEWINAPICreateThread(</p>
<p>LPSECURITY_ATTRIBUTESlpThreadAttributes,</p>
<p>SIZE_TdwStackSize,</p>
<p>LPTHREAD_START_ROUTINElpStartAddress,</p>
<p>LPVOIDlpParameter,</p>
<p>DWORDdwCreationFlags,</p>
<p>LPDWORDlpThreadId</p>
<p>);</p>
<p>函数说明:</p>
<p>第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。</p>
<p>第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。</p>
<p>第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。</p>
<p>第四个参数是传给线程函数的参数。</p>
<p>第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。</p>
<p>第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。</p>
<p>函数返回值:</p>
<p>成功返回新线程的句柄,失败返回NULL。</p>
<p>CreateThread()函数是Windows提供的API接口,在C/C++语言另有一个创建线程的函数_beginthreadex(),在很多书上(包括《Windows核心编程)提到过尽量使用_beginthreadex()来代替使用CreateThread(),这是为什么了?下面就来探索与发现它们的区别吧。</p>
<pre><code>if (system("notepad.exe readme.txt") == -1)
{
switch(errno)
{
...//错误处理代码
}
}
</code></pre>
<p>假设某个线程A在执行上面的代码,该线程在调用system()之后且尚未调用switch()语句时另外一个线程B启动了,这个线程B也调用了标准C运行库的函数,不幸的是这个函数执行出错了并将错误代号写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。这种情况必须要加以避免!因为不单单是这一个变量会出问题,其它像strerror()、strtok()、tmpnam()、gmtime()、asctime()等函数也会遇到这种由多个线程访问修改导致的数据覆盖问题。</p>
<p>为了解决这个问题,Windows操作系统提供了这样的一种解决方案——每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而且这块内存区域的创建就是由C/C++运行库函数_beginthreadex()来负责的。</p>
<pre><code>_MCRTIMP uintptr_t __cdecl _beginthreadex(
void *security,
unsigned stacksize,
unsigned (__CLR_OR_STD_CALL * initialcode) (void *),
void * argument,
unsigned createflag,
unsigned *thrdaddr
)
{
_ptiddata ptd; //pointer to per-thread data 见注1
uintptr_t thdl; //thread handle 线程句柄
unsigned long err = 0L; //Return from GetLastError()
unsigned dummyid; //dummy returned thread ID 线程ID号
// validation section 检查initialcode是否为NULL
_VALIDATE_RETURN(initialcode != NULL, EINVAL, 0);
//Initialize FlsGetValue function pointer
__set_flsgetvalue();
//Allocate and initialize a per-thread data structure for the to-be-created thread.
//相当于new一个_tiddata结构,并赋给_ptiddata指针。
if ( (ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL )
goto error_return;
// Initialize the per-thread data
//初始化线程的_tiddata块即CRT数据区域 见注2
_initptd(ptd, _getptd()->ptlocinfo);
//设置_tiddata结构中的其它数据,这样这块_tiddata块就与线程联系在一起了。
ptd->_initaddr = (void *) initialcode; //线程函数地址
ptd->_initarg = argument; //传入的线程参数
ptd->_thandle = (uintptr_t)(-1);
#if defined (_M_CEE) || defined (MRTDLL)
if(!_getdomain(&(ptd->__initDomain))) //见注3
{
goto error_return;
}
#endif // defined (_M_CEE) || defined (MRTDLL)
// Make sure non-NULL thrdaddr is passed to CreateThread
if ( thrdaddr == NULL )//判断是否需要返回线程ID号
thrdaddr = &dummyid;
// Create the new thread using the parameters supplied by the caller.
//_beginthreadex()最终还是会调用CreateThread()来向系统申请创建线程
if ( (thdl = (uintptr_t)CreateThread(
(LPSECURITY_ATTRIBUTES)security,
stacksize,
_threadstartex,
(LPVOID)ptd,
createflag,
(LPDWORD)thrdaddr))
== (uintptr_t)0 )
{
err = GetLastError();
goto error_return;
}
//Good return
return(thdl); //线程创建成功,返回新线程的句柄.
//Error return
error_return:
//Either ptd is NULL, or it points to the no-longer-necessary block
//calloc-ed for the _tiddata struct which should now be freed up.
//回收由_calloc_crt()申请的_tiddata块
_free_crt(ptd);
// Map the error, if necessary.
// Note: this routine returns 0 for failure, just like the Win32
// API CreateThread, but _beginthread() returns -1 for failure.
//校正错误代号(可以调用GetLastError()得到错误代号)
if ( err != 0L )
_dosmaperr(err);
return( (uintptr_t)0 ); //返回值为NULL的效句柄
}
</code></pre>
<p>讲解下部分代码:</p>
<p>注1._ptiddataptd;中的_ptiddata是个结构体指针。在mtdll.h文件被定义:</p>
<p>typedefstruct_tiddata * _ptiddata</p>
<p>微软对它的注释为Structure for each thread's data。这是一个非常大的结构体,有很多成员。本文由于篇幅所限就不列出来了。</p>
<p>注2._initptd(ptd, _getptd()->ptlocinfo);微软对这一句代码中的getptd()的说明为:</p>
<p>/* return address of per-thread CRT data */</p>
<p>_ptiddata __cdecl_getptd(void);</p>
<p>对_initptd()说明如下:</p>
<p>/* initialize a per-thread CRT data block */</p>
<p>void__cdecl_initptd(<em>Inout</em> _ptiddata _Ptd,<em>In_opt</em> pthreadlocinfo _Locale);</p>
<p>注释中的CRT (C Runtime Library)即标准C运行库。</p>
<p>注3.if(!_getdomain(&(ptd->__initDomain)))中的_getdomain()函数代码可以在thread.c文件中找到,其主要功能是初始化COM环境。</p>
<p>_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。</p>
<p>类似于上面的程序用CreateThread()创建输出“Hello World”的子线程,下面使用_beginthreadex()来创建多个子线程:</p>
<pre><code>#include <stdio.h>
#include <process.h>
#include <windows.h>
unsigned int __stdcall ThreadFun(PVOID pM)
{
printf("线程ID号为%4d的子线程说:Hello World\n", GetCurrentThreadId());
return 0;
}
int main()
{
printf(" 创建多个子线程实例 \n");
printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
const int THREAD_NUM = 5;
HANDLE handle[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
return 0;
}
</code></pre>
<p>原文地址:<a href="http://blog.csdn.net/morewindows/article/details/7421759">http://blog.csdn.net/morewindows/article/details/7421759</a></p>
]]></content>
</entry>
</feed>