Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2862472

Browse files
committed
add android
1 parent 103e4ac commit 2862472

File tree

4 files changed

+277
-1
lines changed

4 files changed

+277
-1
lines changed

Android/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### Android相关分析学习
2+
3+
这里是分析一下相关的安卓源码的地方。
4+
5+
关于如何获取编译代码的方法网络上烂大街。具体操作请参考他们。有没有梯子都可以。
6+
7+
[Android一些同步机制的分析](Android/sync.md)

Android/Sync.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
### 安卓源码阅读编译相关分析
2+
3+
现在 网上有很多编译的教程,我这里就不在赘述。这里主要记录我阅读安卓源码和修改的一些心得体会。
4+
5+
感谢老罗,感谢前人带我入门!
6+
7+
8+
9+
注意,我这里的源代码版本是android - 10.不同代码版本结构稍有不同,这里请自行熟悉。
10+
11+
12+
13+
[安卓中
14+
15+
[同步机制](Android/Sync.md)
16+

Android/sync.md

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
### 安卓当中的同步机制
2+
3+
我们先回忆一下,操作系统中有哪些同步的手段?
4+
5+
- 信号量(Semaphore)
6+
7+
它主要包含两个操作,P和V。 Semaphore 来指示这个共享资源的可用数量,换种理解是,有多少人可以使用这个资源?
8+
9+
P操作可以减少信号量的计数,V操作可以增加计数。P V 这两个操作都是属于原子操作,意味着执行过程不可以被中断。
10+
11+
- 互斥量(Mutex)
12+
13+
简单而言,你可以认为他是简化版的信号量。也就是取值只能为0和1的信号量(Binary Semaphore)。换句话说,操作系统很多时候的资源都具有排他性--这个资源当前要么被占用,要么可以被访问。Mutex相较于Semaphore实现起来也更为简单。
14+
15+
- 管程(Monitor)
16+
17+
- Futex(Fast Userspace mutexs)Linux独有的,好像在早期的某个内核版本被加入。
18+
19+
20+
21+
那么我们来看看Android中有哪些手段吧。
22+
23+
#### Mutex
24+
25+
文件位置:`$ANDROID_CODEBASE/system/core/libutils/include/utils/Mutex.h`,如果下面没有特殊说明,默认我们的路径都是从`$ANDROID_CODEBASE`开始。它表示你的源码根目录。
26+
27+
为了简单,我就摘取一些相关的代码,其他代码有兴趣的可以自行深入分析。
28+
29+
```c++
30+
class CAPABILITY("mutex") Mutex {
31+
public:
32+
enum {
33+
PRIVATE = 0, // 只支持同一个进程间的同步
34+
SHARED = 1 // 支持跨进程间的同步
35+
};
36+
37+
Mutex();
38+
explicit Mutex(const char* name);
39+
explicit Mutex(int type, const char* name = nullptr);
40+
~Mutex();
41+
42+
// lock or unlock the mutex
43+
status_t lock() ACQUIRE();
44+
void unlock() RELEASE();
45+
46+
// lock if possible; returns 0 on success, error otherwise
47+
status_t tryLock() TRY_ACQUIRE(0);
48+
...
49+
```
50+
51+
52+
53+
两个枚举量的意思我已经注释中写明白了,这里只有三个有意思的方法,
54+
55+
```c++
56+
status_t lock();
57+
void unlock();
58+
status_t tryLock();
59+
```
60+
61+
从名字上我们可以看到他们的作用,我们来进一步看看他的实现:
62+
63+
```c++
64+
inline status_t Mutex::lock() {
65+
return -pthread_mutex_lock(&mMutex);
66+
}
67+
inline void Mutex::unlock() {
68+
pthread_mutex_unlock(&mMutex);
69+
}
70+
inline status_t Mutex::tryLock() {
71+
return -pthread_mutex_trylock(&mMutex);
72+
}
73+
```
74+
75+
这里你就会发现,他本质上其实是对pthread的接口做了一些相关的封装 。
76+
77+
#### Condition
78+
79+
这个东西字面意思是条件。他的设计哲学是,判断一个条件是不是满足了?—— 如果满足了,那就返回,继续执行下去,否则就休眠等待。**直到条件被满足**
80+
81+
退一步想想,这种情况能用Mutex做么? 理论上应该可以的。举个例子,假设我们两个线程`A`` B`, 他们会同时修改一个全局变量`var`, 并且我们定义行为:
82+
83+
`Thread A` 不断修改 `var`的值,每次改变之后的值是未知的
84+
85+
`Thread B`观察`var`的值,如果为0了的时候执行某些动作。
86+
87+
我们可以看到, A , B 两个线程都想访问`var`这个资源。Mutex是个思路。但是我们想想,线程B 等待的是当 `var`这个变量为0的情况,醉翁之意不在酒。
88+
89+
如果用Mutex写,类似于这样的:
90+
91+
```c
92+
while (1) { // 死循环
93+
acquire_mutex_lock(var); // 去获取mutex锁
94+
if (var == 0) { // 条件满足
95+
release_mutex_lock(var);
96+
break;
97+
}else {
98+
release_mutex_lock(var); // 下一轮我们再看看
99+
sleep();
100+
}
101+
}
102+
```
103+
104+
所以我们可以看到,这种轮询方式特别耗费CPU时间。
105+
106+
举个例子,假如有两个角色,厕所维护员还有使用厕所的用户,代表上述A B 两个角色。然后我们把厕纸当做变量var。那么出现这种场景,用户随便用厕纸,厕纸的余量是多少未知。但是工作人员等厕纸余量为0的时候,需要去更换厕纸。Mutex的机制下,可以看到,工作人员和普通拉屎的用户一样,都要排队轮询进厕所来看看厕纸。那么可以看到,这个工作人员效率很低,他要跟大家一起排队来获取进入厕所的机会。
107+
108+
那么有一种思路是,工作人员不排队,当厕纸用完了,有个人通知他,叫他进来换厕纸,减少排队数量,提高效率。
109+
110+
Condition就是来解决这类问题的。
111+
112+
- 文件位置:`system/core/libutils/include/utils/Condition.h`
113+
114+
```c++
115+
class Condition {
116+
public:
117+
enum {
118+
PRIVATE = 0, // 和前面类似,也有跨进程共享的支持
119+
SHARED = 1
120+
};
121+
122+
enum WakeUpType {
123+
WAKE_UP_ONE = 0,
124+
WAKE_UP_ALL = 1
125+
};
126+
127+
Condition();
128+
explicit Condition(int type);
129+
~Condition();
130+
// Wait on the condition variable. Lock the mutex before calling.
131+
// Note that spurious wake-ups may happen.
132+
status_t wait(Mutex& mutex); // 在某个条件上等待
133+
// same with relative timeout
134+
status_t waitRelative(Mutex& mutex, nsecs_t reltime); // 同上,但是这里是超时退出
135+
// Signal the condition variable, allowing one thread to continue.
136+
void signal(); // 满足条件了,通知等待者
137+
// Signal the condition variable, allowing one or all threads to continue.
138+
void signal(WakeUpType type) {
139+
if (type == WAKE_UP_ONE) {
140+
signal();
141+
} else {
142+
broadcast();
143+
}
144+
}
145+
// Signal the condition variable, allowing all threads to continue.
146+
void broadcast(); // 条件满足时 通知所有等待者
147+
```
148+
149+
其实如果你英文好的话,看上面的注释你就可以明白了。
150+
151+
这里是个C++的类,那么我们来看看这里的一些关键实现方法。
152+
153+
```c++
154+
inline status_t Condition::wait(Mutex& mutex) {
155+
return -pthread_cond_wait(&mCond, &mutex.mMutex);
156+
}
157+
158+
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
159+
struct timespec ts;
160+
#if defined(__linux__)
161+
clock_gettime(CLOCK_MONOTONIC, &ts); // linux和apple下获取时间的函数,编译相关
162+
#else // __APPLE__
163+
// Apple doesn't support POSIX clocks.
164+
struct timeval t;
165+
gettimeofday(&t, nullptr);
166+
ts.tv_sec = t.tv_sec;
167+
ts.tv_nsec = t.tv_usec*1000;
168+
#endif
169+
170+
// On 32-bit devices, tv_sec is 32-bit, but `reltime` is 64-bit.
171+
int64_t reltime_sec = reltime/1000000000;
172+
173+
ts.tv_nsec += static_cast<long>(reltime%1000000000);
174+
if (reltime_sec < INT64_MAX && ts.tv_nsec >= 1000000000) {
175+
ts.tv_nsec -= 1000000000;
176+
++reltime_sec;
177+
}
178+
179+
int64_t time_sec = ts.tv_sec;
180+
if (time_sec > INT64_MAX - reltime_sec) {
181+
time_sec = INT64_MAX;
182+
} else {
183+
time_sec += reltime_sec;
184+
}
185+
186+
ts.tv_sec = (time_sec > LONG_MAX) ? LONG_MAX : static_cast<long>(time_sec);
187+
188+
return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
189+
}
190+
191+
192+
inline void Condition::signal() {
193+
pthread_cond_signal(&mCond);
194+
}
195+
inline void Condition::broadcast() {
196+
pthread_cond_broadcast(&mCond);
197+
}
198+
199+
```
200+
201+
可以看到,还是pthread的相关接口的封装。
202+
203+
这里留个问题,为什么wait函数的参数还是要用到Mutex呢?
204+
205+
#### Barrier
206+
207+
意思是屏障。接上文我们继续思考,我们来看一个Condition的例子。
208+
209+
Barrier这个东西是为了SurfaceFlinger这个东西设计的,不像Mutex,Condition一样作为Util工具来提供给大家用。不过我们来看看Barrier这个例子。
210+
211+
文件位置:`frameworks/native/services/surfaceflinger/Barrier.h`
212+
213+
```c++
214+
class Barrier
215+
{
216+
public:
217+
// Release any threads waiting at the Barrier.
218+
// Provides release semantics: preceding loads and stores will be visible
219+
// to other threads before they wake up.
220+
void open() {
221+
std::lock_guard<std::mutex> lock(mMutex);
222+
mIsOpen = true;
223+
mCondition.notify_all();
224+
}
225+
226+
// Reset the Barrier, so wait() will block until open() has been called.
227+
void close() {
228+
std::lock_guard<std::mutex> lock(mMutex);
229+
mIsOpen = false;
230+
}
231+
232+
// Wait until the Barrier is OPEN.
233+
// Provides acquire semantics: no subsequent loads or stores will occur
234+
// until wait() returns.
235+
void wait() const {
236+
std::unique_lock<std::mutex> lock(mMutex);
237+
mCondition.wait(lock, [this]() NO_THREAD_SAFETY_ANALYSIS { return mIsOpen; });
238+
}
239+
private:
240+
mutable std::mutex mMutex;
241+
mutable std::condition_variable mCondition;
242+
int mIsOpen GUARDED_BY(mMutex){false};
243+
};
244+
245+
```
246+
247+
可以看到,有三个函数,分别是`wait`, `close`,`open`
248+
249+
既然说它是condition的一个例子,那么barrier等待的条件是什么呢?
250+
251+
答案是 `mIsOpen`。我们来看`wait`函数,他首先获取了一个mutex锁,然后才去调用Condition的`wait`。为什么呢?因为`mIsOpen`这个变量如果没有被互斥锁保护起来的话,`open/close`同时去操作他的话,会发生什么情况呢?
252+
253+
所以这就是整个设计的一个巧妙的地方。

_sidebar.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* [递归学习](recursive/)
77
* [C Style Guide](myself/c_style_guide.md)
88
* [LRU](LRU/lru.md)
9-
109
* [BFS](BFS/)
1110
* [DP](DP/)
11+
* [Android](Android/)
1212

0 commit comments

Comments
 (0)