nonstatic data members在class object中的排列顺序和其被声明的顺序一样,任何介入的static data members都不会被放入到对象布局中。我们也可以对nonstatic 类型的data member取地址,如同static类型的变量一样,假设有一个Obj类,包含一个整型的数据成员b,则我们也可以进行如下操作:
> uname -a Linux net 5.19.0-35-generic #36~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Feb 17 15:17:25 UTC 2 x86_64 x86_64 x86_64 GNU/Linux > g++ --version g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the sourcefor copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""Class that implements a condition variable. A condition variable allows one or more threads to wait until they are notified by another thread. If the lock argument is given and not None, it must be a Lock or RLock object, and it is used as the underlying lock. Otherwise, a new RLock object is created and used as the underlying lock. """
defwait(self, timeout=None): """Wait until notified or until a timeout occurs. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised. This method releases the underlying lock, and then blocks until it is awakened by a notify() or notify_all() call for the same condition variable in another thread, or until the optional timeout occurs. Once awakened or timed out, it re-acquires the lock and returns. When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). When the underlying lock is an RLock, it is not released using its release() method, since this may not actually unlock the lock when it was acquired multiple times recursively. Instead, an internal interface of the RLock class is used, which really unlocks it even when it has been recursively acquired several times. Another internal interface is then used to restore the recursion level when the lock is reacquired. """ # wait时必须尝试获取到_lock ifnot self._is_owned(): raise RuntimeError("cannot wait on un-acquired lock") waiter = _allocate_lock() waiter.acquire() # 获取新分配的锁 self._waiters.append(waiter) # 入队_waiters saved_state = self._release_save() gotit = False try: # restore state no matter what (e.g., KeyboardInterrupt) if timeout isNone: waiter.acquire() gotit = True else: if timeout > 0: gotit = waiter.acquire(True, timeout) else:葡萄 gotit = waiter.acquire(False) return gotit finally: self._acquire_restore(saved_state) ifnot gotit: try: self._waiters.remove(waiter) except ValueError: pass
defnotify(self, n=1): """Wake up one or more threads waiting on this condition, if any. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised. This method wakes up at most n of the threads waiting for the condition variable; it is a no-op if no threads are waiting. """ ifnot self._is_owned(): raise RuntimeError("cannot notify on un-acquired lock") waiters = self._waiters while waiters and n > 0: waiter = waiters[0] # 获取队列首元素并release try: waiter.release() except RuntimeError: # gh-92530: The previous call of notify() released the lock, # but was interrupted before removing it from the queue. # It can happen if a signal handler raises an exception, # like CTRL+C which raises KeyboardInterrupt. pass else: n -= 1 try: waiters.remove(waiter) # 移除该锁 except ValueError: pass
"""This class implements reentrant lock objects. A reentrant lock must be released by the thread that acquired it. Once a thread has acquired a reentrant lock, the same thread may acquire it again without blocking; the thread must release it once for each time it has acquired it. """
defacquire(self, blocking=True, timeout=-1): """Acquire a lock, blocking or non-blocking. When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case. When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return true. When invoked with the blocking argument set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true. When invoked with the floating-point timeout argument set to a positive value, block for at most the number of seconds specified by timeout and as long as the lock cannot be acquired. Return true if the lock has been acquired, false if the timeout has elapsed. """ me = get_ident() if self._owner == me: # 如果已经拥有该锁,递增_count self._count += 1 return1 rc = self._block.acquire(blocking, timeout) # 尝试获取锁 if rc: self._owner = me self._count = 1
defrelease(self): """Release a lock, decrementing the recursion level. If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread. Only call this method when the calling thread owns the lock. A RuntimeError is raised if this method is called when the lock is unlocked. There is no return value. """ if self._owner != get_ident(): # 检查是否当前线程是锁的拥有者 raise RuntimeError("cannot release un-acquired lock") self._count = count = self._count - 1# 递减count ifnot count: # count为0则释放锁 self._owner = None self._block.release()
classbase { friendbooloperator==(const base &lhs, const base &rhs) { returntypeid(lhs) == typeid(rhs) && lhs.equal(rhs); }
friendbooloperator!=(const base &lhs, const base &rhs) { return !(lhs == rhs); }
public: base() = default; base(int _a) : a(_a) { } virtualboolequal(const base &rhs)const { return a == rhs.a; }
private: int a{}; };
classderived : public base { public: derived() = default; derived(int _a, int _b) : base(_a), b(_b) { } boolequal(const base &rhs)const { auto r = dynamic_cast<const derived &>(rhs); return base::equal(rhs) && b == r.b; }
private: int b{}; };
intmain() { // case 1: base != derived derived d1(1, 2); base b1(1); assert(d1 != b1);
// case 2: base != base base b2(1); base b3(2); assert(b2 != b3);
// case 3: base == base base b4(13); base b5(13); assert(b4 == b5);
classObj : public Base1, public Base2 { public: int a; uint8_t b; virtualvoidbase1_virt1() { cout << hex << this << " Obj 1 virtfunc1 from base 1\n"; }
virtualvoidbase2_virt1() { cout << hex << this <<" Obj 1 virtfunc1 from base 2\n"; }
> cat bar this is history1 this is history2 this is history3 rda@pa ~/T/test (master)> cat foo this is history1 this is history2 this is history3
我们将基于这两个文件原有的内容做简单的添加,以及执行reset和checkout,探究两者的功能和差异。本文不涉及介绍git中指针,头指针的操作和其他概念。 在foo文件尾添加”this is stage”的文本,并执行git add foo,暂存该修改,然后再在文件尾添加”this is work dir”的文本
1 2 3
> echo'this is stage' >> foo > git add foo > echo'this is work dir' >> foo
执行git diff,查看工作目录和暂存区的差别
1 2 3 4 5 6 7 8 9 10
> git diff diff --git a/foo b/foo index fc8c574..64512a0 100644 --- a/foo +++ b/foo @@ -2,3 +2,4 @@ this is history1 this is history2 this is history3 this is stage +this is work dir
执行git diff –staged,查看暂存区和仓库的差别
1 2 3 4 5 6 7 8 9 10
> git diff --staged diff --git a/foo b/foo index 55a27cf..fc8c574 100644 --- a/foo +++ b/foo @@ -1,3 +1,4 @@ this is history1 this is history2 this is history3 +this is stage
可见,相对于仓库,暂存区中添加了文本”this is stage”,而相对于暂存区,工作目录添加了”this is work dir”,同理,执行git diff HEAD,对比工作目录和仓库,文件foo追加了两条字符串
1 2 3 4 5 6 7 8 9 10 11
> git diff HEAD diff --git a/foo b/foo index 55a27cf..64512a0 100644 --- a/foo +++ b/foo @@ -1,3 +1,5 @@ this is history1 this is history2 this is history3 +this is stage +this is work dir
我们也可以执行git status -s,左边显示的M表示foo已经修改并暂存,右边的M表示foo再暂存后又有新的修改
git reset --hard HEAD HEAD is now at cabad03 history3 > git diff > git diff --staged > git diff HEAD > cat foo this is history1 this is history2 this is history3 > git status On branch master nothing to commit, working tree clean
可见,工作目录、暂存区和仓库的内容是一致的。 可以使用该命令“回退”到某一历史commit
1 2 3 4 5 6 7 8
> git reset --hard HEAD~ HEAD is now at 0c52905 history2 > git status On branch master nothing to commit, working tree clean > git log --pretty=oneline 0c5290517531ada5847cc418e9db2941e33fb62e (HEAD -> master) history2 f010d6d2831e827a16d4687076cf2de40f89076d history1
> git diff diff --git a/foo b/foo index 4c1d2ab..bd45079 100644 --- a/foo +++ b/foo @@ -1,3 +1,4 @@ this is history1 this is history2 this is stage +this is work dir > git diff --staged diff --git a/foo b/foo index 8e02c46..4c1d2ab 100644 --- a/foo +++ b/foo @@ -1,2 +1,3 @@ this is history1 this is history2 +this is stage > git diff HEAD diff --git a/foo b/foo index 8e02c46..bd45079 100644 --- a/foo +++ b/foo @@ -1,2 +1,4 @@ this is history1 this is history2 +this is stage +this is work dir
> git diff diff --git a/foo b/foo index 8e02c46..bd45079 100644 --- a/foo +++ b/foo @@ -1,2 +1,4 @@ this is history1 this is history2 +this is stage +this is work dir > git diff --staged > git diff HEAD diff --git a/foo b/foo index 8e02c46..bd45079 100644 --- a/foo +++ b/foo @@ -1,2 +1,4 @@ this is history1 this is history2 +this is stage +this is work dir
此时,原本已经暂存的内容也被丢弃,算作了工作目录和上一次提交的差异。–mixed是默认项,因此可以省略。 执行git reset HEAD~,预期该指令执行结果是: for:暂存区内容和第一次提交内容一致,均为”this is history1”,而工作目录不变,追加了三条字符串,分别是”this is history2””this is stage””this is work dir” bar:暂存区和第一次提交一致,工作目录中的”this is history2”为新加的内容
1 2 3 4
> git reset HEAD~ Unstaged changes after reset: M bar M foo
> git diff diff --git a/bar b/bar index 361b0e4..8e02c46 100644 --- a/bar +++ b/bar @@ -1 +1,2 @@ this is history1 +this is history2 diff --git a/foo b/foo index 361b0e4..bd45079 100644 --- a/foo +++ b/foo @@ -1 +1,4 @@ this is history1 +this is history2 +this is stage +this is work dir > git diff --staged > git diff HEAD diff --git a/bar b/bar index 361b0e4..8e02c46 100644 --- a/bar +++ b/bar @@ -1 +1,2 @@ this is history1 +this is history2 diff --git a/foo b/foo index 361b0e4..bd45079 100644 --- a/foo +++ b/foo @@ -1 +1,4 @@ this is history1 +this is history2 +this is stage +this is work dir
soft
git reset –soft会重置repository,但保留stage、workspace中的改动。 首先将仓库恢复到初始状态,即有三次commit,并且暂存区中有”this is stage”,工作目录中还额外添加了”this is work dir”。恢复的方法是,根据第三次commit,checkout到commit3(checkout可以移动HEAD指针,然后在commit3处新建一个分支,并将master合并到该分支即可) 执行git reset –soft HEAD~2,即reset到第一次commit,预期执行结果是: foo文件:仓库仅有”this is history1”,暂存区中有”this is history2””this is history3””this is stage”,而工作目录额外有”this is work dir” bar文件:仓库仅有”this is history1”,暂存区中有”this is history2””this is history3”,工作目录与暂存区内容一致
1
> git reset --soft HEAD~2
查看两个文件内容
1 2 3 4 5 6 7 8 9 10
> cat bar this is history1 this is history2 this is history3 > cat foo this is history1 this is history2 this is history3 this is stage this is work dir
> git diff diff --git a/foo b/foo index fc8c574..64512a0 100644 --- a/foo +++ b/foo @@ -2,3 +2,4 @@ this is history1 this is history2 this is history3 this is stage +this is work dir > git diff --staged diff --git a/bar b/bar index 361b0e4..55a27cf 100644 --- a/bar +++ b/bar @@ -1 +1,3 @@ this is history1 +this is history2 +this is history3 diff --git a/foo b/foo index 361b0e4..fc8c574 100644 --- a/foo +++ b/foo @@ -1 +1,4 @@ this is history1 +this is history2 +this is history3 +this is stage > git diff HEAD diff --git a/bar b/bar index 361b0e4..55a27cf 100644 --- a/bar +++ b/bar @@ -1 +1,3 @@ this is history1 +this is history2 +this is history3 diff --git a/foo b/foo index 361b0e4..64512a0 100644 --- a/foo +++ b/foo @@ -1 +1,5 @@ this is history1 +this is history2 +this is history3 +this is stage +this is work dir
> echo'this is stage' >> foo > echo'this is stage' >> bar > git add foo bar > echo'this is work dir' >> foo > echo'this is work dir' >> bar > git status -s MM bar MM foo
> git checkout HEAD foo Updated 1 path from 3ea0ad5 > git diff diff --git a/bar b/bar index fc8c574..64512a0 100644 --- a/bar +++ b/bar @@ -2,3 +2,4 @@ this is history1 this is history2 this is history3 this is stage +this is work dir > git diff --staged diff --git a/bar b/bar index 55a27cf..fc8c574 100644 --- a/bar +++ b/bar @@ -1,3 +1,4 @@ this is history1 this is history2 this is history3 +this is stage
可见,foo的暂存区和工作目录被HEAD处的提交覆盖了,相当于丢弃了暂存区和工作目录中的修改,而bar未受影响 同样,我们对bar进行操作,首先将仓库的状态恢复到初始状态。 执行git checkout HEAD~2 bar
1 2
> git checkout HEAD~2 bar Updated 1 path from f6fa925
> git diff foo diff --git a/foo b/foo index fc8c574..64512a0 100644 --- a/foo +++ b/foo @@ -2,3 +2,4 @@ this is history1 this is history2 this is history3 this is stage +this is work dir > git diff --staged foo diff --git a/foo b/foo index 55a27cf..fc8c574 100644 --- a/foo +++ b/foo @@ -1,3 +1,4 @@ this is history1 this is history2 this is history3 +this is stage > git diff HEAD foo diff --git a/foo b/foo index 55a27cf..64512a0 100644 --- a/foo +++ b/foo @@ -1,3 +1,5 @@ this is history1 this is history2 this is history3 +this is stage +this is work dir
未受到影响。 查看bar文件的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> git diff bar > git diff --staged bar diff --git a/bar b/bar index 55a27cf..361b0e4 100644 --- a/bar +++ b/bar @@ -1,3 +1 @@ this is history1 -this is history2 -this is history3 > git diff HEAD bar diff --git a/bar b/bar index 55a27cf..361b0e4 100644 --- a/bar +++ b/bar @@ -1,3 +1 @@ this is history1 -this is history2 -this is history3
voidprint_cache() { for (int i = 0; i < NUM_CORE; ++i) printf("[%d] %c %d\n", i, state_ch[cache[i].state], cache[i].data); for (int i = 0; i < 4; ++i) printf("%c %d\t", state_ch[i], state_count[i]); printf("\nmemory: %d\n", mem_data); }
// if S state count is 1, update it to E if (state_count[SHARED] == 1) { for (int i = 0; i < NUM_CORE; ++i) if (cache[i].state == SHARED) { cache[i].state = EXCLUSIVE; --state_count[SHARED]; ++state_count[EXCLUSIVE]; exclusive_idx = i; break; } } }
> ./mesi 5 ======================================== evict line <1> [1] evict
[0] I 0 [1] I 0 [2] I 0 [3] I 0 M 0 E 0 S 0 I 4 memory: 6828 ======================================== evict line <1> [1] evict
[0] I 0 [1] I 0 [2] I 0 [3] I 0 M 0 E 0 S 0 I 4 memory: 6828 ======================================== read line <3> [3] read miss; read from memory data 6828
[0] I 0 [1] I 0 [2] I 0 [3] E 6828 M 0 E 1 S 0 I 3 memory: 6828 ======================================== write line <3> [3] write hit; write data 7815
[0] I 0 [1] I 0 [2] I 0 [3] M 7815 M 1 E 0 S 0 I 3 memory: 6828 ======================================== write line <1> [1] write miss [3] write back 7815 [1] read from memory 7815; update to 5828
[0] I 0 [1] M 5828 [2] I 0 [3] I 7815 M 1 E 0 S 0 I 3 memory: 7815 pass
> ./false_sharing T[140737351505472] run on core <0> result 0x55558040: 100000000 T[140737343112768] run on core <1> result 0x55558080: 100000000 ======================[NO] cost 1646328 T[140737343112768] run on core <0> result 0x555580c0: 100000000 T[140737351505472] run on core <1> result 0x555580c8: 100000000 ======================[FALSE] cost 2323293 T[140737343112768] run on core <1> result 0x55558100: 124568282 T[140737351505472] run on core <0> result 0x55558100: 142349628 ======================[TRUE] cost 3019775