小凡156

博客园 首页 新随笔 联系 订阅 管理
  1 // Consider:
  2 
  3 // If the lock is cool (cxq == null && succ == null) and we're on an MP system
  4 
  5 // then instead of transferring a thread from the WaitSet to the EntryList
  6 
  7 // we might just dequeue a thread from the WaitSet and directly unpark() it.
  8 
  9 
 10 void ObjectMonitor::notify(TRAPS) {
 11 
 12   CHECK_OWNER();
 13 
 14   if (_WaitSet == NULL) {
 15 
 16      TEVENT (Empty-Notify) ;
 17 
 18      return ;
 19 
 20   }
 21 
 22   DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
 23 
 24   注意Policy的赋值
 25   int Policy = Knob_MoveNotifyee ;
 26 
 27 
 28   Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
 29   调用DequeueWaiter()方法将_WaitSet队列的第一个值取出并返回
 30   ObjectWaiter * iterator = DequeueWaiter() ;
 31 
 32   if (iterator != NULL) {
 33 
 34      TEVENT (Notify1 - Transfer) ;
 35 
 36      guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
 37 
 38      guarantee (iterator->_notified == 0, "invariant") ;
 39 
 40      if (Policy != 4) {
 41 
 42         iterator->TState = ObjectWaiter::TS_ENTER ;
 43 
 44      }
 45 
 46      iterator->_notified = 1 ;
 47 
 48      Thread * Self = THREAD;
 49 
 50      iterator->_notifier_tid = Self->osthread()->thread_id();
 51 
 52 
 53      ObjectWaiter * List = _EntryList ;
 54 
 55      if (List != NULL) {
 56 
 57         assert (List->_prev == NULL, "invariant") ;
 58 
 59         assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
 60 
 61         assert (List != iterator, "invariant") ;
 62 
 63      }
 64 
 65      Policy == 0:放入_EntryList队列的排头位置;
 66      if (Policy == 0) {       // prepend to EntryList
 67 
 68          if (List == NULL) {
 69 
 70              iterator->_next = iterator->_prev = NULL ;
 71 
 72              _EntryList = iterator ;
 73 
 74          } else {
 75 
 76              List->_prev = iterator ;
 77 
 78              iterator->_next = List ;
 79 
 80              iterator->_prev = NULL ;
 81 
 82              _EntryList = iterator ;
 83 
 84         }
 85 
 86      } else
 87    Policy == 1:放入_EntryList队列的末尾位置;
 88      if (Policy == 1) {      // append to EntryList
 89 
 90          if (List == NULL) {
 91 
 92              iterator->_next = iterator->_prev = NULL ;
 93 
 94              _EntryList = iterator ;
 95 
 96          } else {
 97 
 98             // CONSIDER:  finding the tail currently requires a linear-time walk of
 99 
100             // the EntryList.  We can make tail access constant-time by converting to
101 
102             // a CDLL instead of using our current DLL.
103 
104             ObjectWaiter * Tail ;
105 
106             for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
107 
108             assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
109 
110             Tail->_next = iterator ;
111 
112             iterator->_prev = Tail ;
113 
114             iterator->_next = NULL ;
115 
116         }
117 
118      } else
119    Policy == 2:_EntryList队列为空就放入_EntryList,否则放入_cxq队列的排头位置;
    请注意把ObjectWaiter的地址写到_cxq变量的时候要用CAS操作,因为此时可能有其他线程正在竞争锁,竞争失败的时候会将自己包装成ObjectWaiter对象加入到_cxq中;
120 if (Policy == 2) { // prepend to cxq 121 122 // prepend to cxq 123 124 if (List == NULL) { 125 126 iterator->_next = iterator->_prev = NULL ; 127 128 _EntryList = iterator ; 129 130 } else { 131 132 iterator->TState = ObjectWaiter::TS_CXQ ; 133 134 for (;;) { 135 136 ObjectWaiter * Front = _cxq ; 137 138 iterator->_next = Front ; 139 140 if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) { 141 142 break ; 143 144 } 145 146 } 147 148 } 149 150 } else 151    Policy == 3:放入_cxq队列中,末尾位置; 152 if (Policy == 3) { // append to cxq 153 154 iterator->TState = ObjectWaiter::TS_CXQ ; 155 156 for (;;) { 157 158 ObjectWaiter * Tail ; 159 160 Tail = _cxq ; 161 162 if (Tail == NULL) { 163 164 iterator->_next = NULL ; 165 166 if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) { 167 168 break ; 169 170 } 171 172 } else { 173 174 while (Tail->_next != NULL) Tail = Tail->_next ; 175 176 Tail->_next = iterator ; 177 178 iterator->_prev = Tail ; 179 180 iterator->_next = NULL ; 181 182 break ; 183 184 } 185 186 } 187 188 } else { 189      Policy等于其他值,立即唤醒ObjectWaiter对应的线程; 190 ParkEvent * ev = iterator->_event ; 191 192 iterator->TState = ObjectWaiter::TS_RUN ; 193 194 OrderAccess::fence() ; 195 196 ev->unpark() ; 197 198 } 199 200 201 if (Policy < 4) { 202 203 iterator->wait_reenter_begin(this); 204 205 } 206 207 208 // _WaitSetLock protects the wait queue, not the EntryList. We could 209 210 // move the add-to-EntryList operation, above, outside the critical section 211 212 // protected by _WaitSetLock. In practice that's not useful. With the 213 214 // exception of wait() timeouts and interrupts the monitor owner 215 216 // is the only thread that grabs _WaitSetLock. There's almost no contention 217 218 // on _WaitSetLock so it's not profitable to reduce the length of the 219 220 // critical section. 221 222 } 223 224 225 Thread::SpinRelease (&_WaitSetLock) ; 226 227 228 if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) { 229 230 ObjectMonitor::_sync_Notifications->inc() ; 231 232 } 233 234 }

对ObjectWaiter对象的处理方式,根据Policy的不同而不同:
Policy == 0:放入_EntryList队列的排头位置;
Policy == 1:放入_EntryList队列的末尾位置;
Policy == 2:_EntryList队列为空就放入_EntryList,否则放入_cxq队列的排头位置;

Policy == 3:放入_cxq队列中,末尾位置;更新_cxq变量的值的时候,同样要通过CAS注意并发问题;

Policy等于其他值,立即唤醒ObjectWaiter对应的线程;

 

总结执行notify时的内容:

1. 执行过wait的线程都 在队列_WaitSet中,此处从_WaitSet中取出第一个;

2. 根据Policy的不同,将这个线程放入_EnterList或者_cxq队列中的起始或末尾位置;

posted on 2019-11-10 16:03  小凡156  阅读(291)  评论(0编辑  收藏  举报