sql join
什么是语言 ?
inductively defined sets
inductively defined sets 是由三部分组成
- 1 一个初始集合
- 2 一个生成规则
- 3 声明除了这个1 2两个条件之外没有其他的元素属于这个集合
例子
自然数集合
{0 , 1 , 2 ...}
这个集合 首先一个元素
{0}
然后是规则
suc(i)
left join 和right join的区别?
我是大学学通信工程的,有些数学概念还是不太全,只能偶尔补一下啦.
我一直找left join 和right join的定义或者rfc文件.
就像c语言看c89 c99一样,你看sql也可以看sql 99, 这个文档有描述什么是left join
Let XN1 and XN2 be effective distinct names for X1 and X2, respectively. Let TN be an effective
name for T.
Case:
a) If INNER or <cross join> is specified, then let S be the multiset of rows of T.
b) If LEFT is specified, then let S be the multiset of rows resulting from:
SELECT FROM T
UNION ALL
SELECT FROM X1
c) If RIGHT is specified, then let S be the multiset of rows resulting from:
SELECT FROM T
UNION ALL
SELECT FROM X2
相关阅读
group_concat看mysql函数
bm25 and search
c auto cast
fst
背景
FST 即finite state machine,lucene很多内容都是用这个格式压缩和存储的.
fst 例子
介绍FST之前,先看看Hashmap.
HashMap的语义: key-> value , 也就是输入一个key,返回一个value
FST结构也是一个特别的Map, 语义和Map差不多:FST(key)=value
例子
有下面组词汇的数组[cat:5,dog:7,dogs:13]
- key为
cat,value为5 - key为
dog,value为7 - key为
dogs,value为13
最后会被序列化成这个结构
[0, 116, 15, 97, 6, 5, 115, 31, 103, 7, 111, 6, 7, 100, 22, 4, 5, 99, 16]
下面来分析这个例子的每个字节
| 103, 7 | 111, 6 | 7, 100, 22 | 4, 5, 99, 16 |
|---|---|---|---|
| flag=7,value:'g'也就是103,target:7,nextArch=7 | flag=6,value:'0'也就是111,target:9,nextArch=9 | flag=22 , value='d' 也就是100,output=7,target=11(为什么是11 ?因为7前面就是pos=11,nextArc=11) | flag=16 , value:'c'也就是99, output =5,target=4,nextArc=14 |
[0, 116, 15,| 97, 6, |5, 115, 31, |103, 7, |111, 6, |7, 100, 22,| 4, 5, 99, 16]
--------| ------- | -----------| ------ | ------- |--------- | -------------
(t,null)| (a,null)| (s,5) | (g,null)| (o,null)| (d:7) | (output =5,target=4,flag=16 value:'c')
常量解释:
| 常量 | 值 | 描述 |
|---|---|---|
| BIT_LAST_ARC | 1>>1 | 描述该弧是最后一个弧,类似:二叉树右子节点;或者类似于三叉树的第三个节点 |
| BIT_ARC_HAS_OUTPUT | 1>>4 | 有output,也就是这个节点存了一些值 |
| BIT_TARGET_NEXT | 1>>2 | 表示该节点的下一个节点就是下一个bit,不需要在另外存了,也就是这个弧的两个节点是存在一起的 |
arc class分析
arc class 源码如下:
public static final class Arc<T> {
// *** Arc fields.
private int label;
private T output;
private long target;
private byte flags;
private T nextFinalOutput;
private long nextArc;
private byte nodeFlags;
// *** Fields for arcs belonging to a node with fixed length arcs.
// So only valid when bytesPerArc != 0.
// nodeFlags == ARCS_FOR_BINARY_SEARCH || nodeFlags == ARCS_FOR_DIRECT_ADDRESSING.
private int bytesPerArc;
private long posArcsStart;
private int arcIdx;
private int numArcs;
// *** Fields for a direct addressing node. nodeFlags == ARCS_FOR_DIRECT_ADDRESSING.
/**
* Start position in the {@link FST.BytesReader} of the presence bits for a direct addressing
* node, aka the bit-table
*/
private long bitTableStart;
/** First label of a direct addressing node. */
private int firstLabel;
/**
* Index of the current label of a direct addressing node. While {@link #arcIdx} is the current
* index in the label range, {@link #presenceIndex} is its corresponding index in the list of
* actually present labels. It is equal to the number of bits set before the bit at {@link
* #arcIdx} in the bit-table. This field is a cache to avoid to count bits set repeatedly when
* iterating the next arcs.
*/
private int presenceIndex;
}
| 字段 | 描述 |
|---|---|
| label | 如果用map的key value来举例 , label就是key的一截 , 多个lebel会组成一个key , 举例 "cat" 会拆分成三个label : "c" , "a", "t" |
| output | 如果是用map的key value来举例 , output就是value的一截,多个output会组成一个value |
| target | 描述的是下一个节点的偏移量,一个弧度如果是src -> dst 这样结构的话 , target 就是dst 的位置 也就是 arr[target] 就是dst 的节点的位置 |
| flags | 各种奇奇怪怪的标志位来标识这个弧的状态,用位图来将各种状态压缩 |
| nextFinalOutput | 前面说了,如果这个key value 结构 , 这个描述的是value的最后一截 ,否则就是null |
| nextArc | 描述的是多个弧,就像一个多叉树的兄弟节点,这个是描述下一个兄弟节点的偏移位置 |
| numArcs | 描述的是这个阶段有多少个弧,也就是这个节点有多少个子节点 |
写入过程:
add:473, FSTCompiler (org.apache.lucene.util.fst)
compileIndex:504, Lucene90BlockTreeTermsWriter$PendingBlock (org.apache.lucene.codecs.lucene90.blocktree)
writeBlocks:725, Lucene90BlockTreeTermsWriter$TermsWriter (org.apache.lucene.codecs.lucene90.blocktree)
finish:1105, Lucene90BlockTreeTermsWriter$TermsWriter (org.apache.lucene.codecs.lucene90.blocktree)
write:370, Lucene90BlockTreeTermsWriter (org.apache.lucene.codecs.lucene90.blocktree)
write:172, PerFieldPostingsFormat$FieldsWriter (org.apache.lucene.codecs.perfield)
flush:135, FreqProxTermsWriter (org.apache.lucene.index)
flush:310, IndexingChain (org.apache.lucene.index)
flush:392, DocumentsWriterPerThread (org.apache.lucene.index)
doFlush:492, DocumentsWriter (org.apache.lucene.index)
flushAllThreads:671, DocumentsWriter (org.apache.lucene.index)
doFlush:4194, IndexWriter (org.apache.lucene.index)
flush:4168, IndexWriter (org.apache.lucene.index)
shutdown:1322, IndexWriter (org.apache.lucene.index)
close:1362, IndexWriter (org.apache.lucene.index)
doTestSearch:133, FstTest (com.dinosaur.lucene.demo)
findTargetArc:1418, FST (org.apache.lucene.util.fst)
seekExact:511, SegmentTermsEnum (org.apache.lucene.codecs.lucene90.blocktree)
loadTermsEnum:111, TermStates (org.apache.lucene.index)
build:96, TermStates (org.apache.lucene.index)
createWeight:227, TermQuery (org.apache.lucene.search)
createWeight:904, IndexSearcher (org.apache.lucene.search)
search:687, IndexSearcher (org.apache.lucene.search)
searchAfter:523, IndexSearcher (org.apache.lucene.search)
search:538, IndexSearcher (org.apache.lucene.search)
doPagingSearch:158, SearchFiles (com.dinosaur.lucene.demo)
testSearch:128, SearchFiles (com.dinosaur.lucene.demo)
跳转内容
如何跳转
public void decodeMetaData() throws IOException {
// if (DEBUG) System.out.println("\nBTTR.decodeMetadata seg=" + segment + " mdUpto=" +
// metaDataUpto + " vs termBlockOrd=" + state.termBlockOrd);
// lazily catch up on metadata decode:
final int limit = getTermBlockOrd();
boolean absolute = metaDataUpto == 0;
assert limit > 0;
// TODO: better API would be "jump straight to term=N"???
while (metaDataUpto < limit) {
// TODO: we could make "tiers" of metadata, ie,
// decode docFreq/totalTF but don't decode postings
// metadata; this way caller could get
// docFreq/totalTF w/o paying decode cost for
// postings
// TODO: if docFreq were bulk decoded we could
// just skipN here:
if (statsSingletonRunLength > 0) {
state.docFreq = 1;
state.totalTermFreq = 1;
statsSingletonRunLength--;
} else {
int token = statsReader.readVInt();
if ((token & 1) == 1) {
state.docFreq = 1;
state.totalTermFreq = 1;
statsSingletonRunLength = token >>> 1;
} else {
state.docFreq = token >>> 1;
if (ste.fr.fieldInfo.getIndexOptions() == IndexOptions.DOCS) {
state.totalTermFreq = state.docFreq;
} else {
state.totalTermFreq = state.docFreq + statsReader.readVLong();
}
}
}
// metadata
ste.fr.parent.postingsReader.decodeTerm(bytesReader, ste.fr.fieldInfo, state, absolute);
metaDataUpto++;
absolute = false;
}
state.termBlockOrd = metaDataUpto;
}
相关阅读
- https://www.shenyanchao.cn/blog/2018/12/04/lucene-fst/
- https://blog.csdn.net/wang_hnust/article/details/87950746
- https://blog.51cto.com/sbp810050504/1361551
- https://developer.aliyun.com/article/906165
- https://blog.csdn.net/conansonic/article/details/52091301
- 证明论文
- 知乎相关论文
- https://cs.nyu.edu/~mohri/pub/hwa.pdf
java-wait-notify
背景
java的线程间通信,偶尔会用到wait和notify
实现
注册:
// Register native methods of Object
void java_lang_Object::register_natives(TRAPS) {
InstanceKlass* obj = vmClasses::Object_klass();
Method::register_native(obj, vmSymbols::hashCode_name(),
vmSymbols::void_int_signature(), (address) &JVM_IHashCode, CHECK);
Method::register_native(obj, vmSymbols::wait_name(),
vmSymbols::long_void_signature(), (address) &JVM_MonitorWait, CHECK);
Method::register_native(obj, vmSymbols::notify_name(),
vmSymbols::void_method_signature(), (address) &JVM_MonitorNotify, CHECK);
Method::register_native(obj, vmSymbols::notifyAll_name(),
vmSymbols::void_method_signature(), (address) &JVM_MonitorNotifyAll, CHECK);
Method::register_native(obj, vmSymbols::clone_name(),
vmSymbols::void_object_signature(), (address) &JVM_Clone, THREAD);
}
// -----------------------------------------------------------------------------
// Wait/Notify/NotifyAll
//
// Note: a subset of changes to ObjectMonitor::wait()
// will need to be replicated in complete_exit
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
JavaThread* current = THREAD;
assert(InitDone, "Unexpectedly not initialized");
CHECK_OWNER(); // Throws IMSE if not owner.
EventJavaMonitorWait event;
// check for a pending interrupt
if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
// post monitor waited event. Note that this is past-tense, we are done waiting.
if (JvmtiExport::should_post_monitor_waited()) {
// Note: 'false' parameter is passed here because the
// wait was not timed out due to thread interrupt.
JvmtiExport::post_monitor_waited(current, this, false);
// In this short circuit of the monitor wait protocol, the
// current thread never drops ownership of the monitor and
// never gets added to the wait queue so the current thread
// cannot be made the successor. This means that the
// JVMTI_EVENT_MONITOR_WAITED event handler cannot accidentally
// consume an unpark() meant for the ParkEvent associated with
// this ObjectMonitor.
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, 0, millis, false);
}
THROW(vmSymbols::java_lang_InterruptedException());
return;
}
assert(current->_Stalled == 0, "invariant");
current->_Stalled = intptr_t(this);
current->set_current_waiting_monitor(this);
// create a node to be put into the queue
// Critically, after we reset() the event but prior to park(), we must check
// for a pending interrupt.
ObjectWaiter node(current);
node.TState = ObjectWaiter::TS_WAIT;
current->_ParkEvent->reset();
OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
// Enter the waiting queue, which is a circular doubly linked list in this case
// but it could be a priority queue or any data structure.
// _WaitSetLock protects the wait queue. Normally the wait queue is accessed only
// by the the owner of the monitor *except* in the case where park()
// returns because of a timeout of interrupt. Contention is exceptionally rare
// so we use a simple spin-lock instead of a heavier-weight blocking lock.
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - add");
AddWaiter(&node);
Thread::SpinRelease(&_WaitSetLock);
_Responsible = NULL;
intx save = _recursions; // record the old recursion count
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
exit(current); // exit the monitor
guarantee(owner_raw() != current, "invariant");
// The thread is on the WaitSet list - now park() it.
// On MP systems it's conceivable that a brief spin before we park
// could be profitable.
//
// TODO-FIXME: change the following logic to a loop of the form
// while (!timeout && !interrupted && _notified == 0) park()
int ret = OS_OK;
int WasNotified = 0;
// Need to check interrupt state whilst still _thread_in_vm
bool interrupted = interruptible && current->is_interrupted(false);
{ // State transition wrappers
OSThread* osthread = current->osthread();
OSThreadWaitState osts(osthread, true);
assert(current->thread_state() == _thread_in_vm, "invariant");
{
ClearSuccOnSuspend csos(this);
ThreadBlockInVMPreprocess<ClearSuccOnSuspend> tbivs(current, csos, true /* allow_suspend */);
if (interrupted || HAS_PENDING_EXCEPTION) {
// Intentionally empty
} else if (node._notified == 0) {
if (millis <= 0) {
current->_ParkEvent->park();
} else {
ret = current->_ParkEvent->park(millis);
}
}
}
// Node may be on the WaitSet, the EntryList (or cxq), or in transition
// from the WaitSet to the EntryList.
// See if we need to remove Node from the WaitSet.
// We use double-checked locking to avoid grabbing _WaitSetLock
// if the thread is not on the wait queue.
//
// Note that we don't need a fence before the fetch of TState.
// In the worst case we'll fetch a old-stale value of TS_WAIT previously
// written by the is thread. (perhaps the fetch might even be satisfied
// by a look-aside into the processor's own store buffer, although given
// the length of the code path between the prior ST and this load that's
// highly unlikely). If the following LD fetches a stale TS_WAIT value
// then we'll acquire the lock and then re-fetch a fresh TState value.
// That is, we fail toward safety.
if (node.TState == ObjectWaiter::TS_WAIT) {
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - unlink");
if (node.TState == ObjectWaiter::TS_WAIT) {
DequeueSpecificWaiter(&node); // unlink from WaitSet
assert(node._notified == 0, "invariant");
node.TState = ObjectWaiter::TS_RUN;
}
Thread::SpinRelease(&_WaitSetLock);
}
// The thread is now either on off-list (TS_RUN),
// on the EntryList (TS_ENTER), or on the cxq (TS_CXQ).
// The Node's TState variable is stable from the perspective of this thread.
// No other threads will asynchronously modify TState.
guarantee(node.TState != ObjectWaiter::TS_WAIT, "invariant");
OrderAccess::loadload();
if (_succ == current) _succ = NULL;
WasNotified = node._notified;
// Reentry phase -- reacquire the monitor.
// re-enter contended monitor after object.wait().
// retain OBJECT_WAIT state until re-enter successfully completes
// Thread state is thread_in_vm and oop access is again safe,
// although the raw address of the object may have changed.
// (Don't cache naked oops over safepoints, of course).
// post monitor waited event. Note that this is past-tense, we are done waiting.
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT);
if (node._notified != 0 && _succ == current) {
// In this part of the monitor wait-notify-reenter protocol it
// is possible (and normal) for another thread to do a fastpath
// monitor enter-exit while this thread is still trying to get
// to the reenter portion of the protocol.
//
// The ObjectMonitor was notified and the current thread is
// the successor which also means that an unpark() has already
// been done. The JVMTI_EVENT_MONITOR_WAITED event handler can
// consume the unpark() that was done when the successor was
// set because the same ParkEvent is shared between Java
// monitors and JVM/TI RawMonitors (for now).
//
// We redo the unpark() to ensure forward progress, i.e., we
// don't want all pending threads hanging (parked) with none
// entering the unlocked monitor.
node._event->unpark();
}
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, node._notifier_tid, millis, ret == OS_TIMEOUT);
}
OrderAccess::fence();
assert(current->_Stalled != 0, "invariant");
current->_Stalled = 0;
assert(owner_raw() != current, "invariant");
ObjectWaiter::TStates v = node.TState;
if (v == ObjectWaiter::TS_RUN) {
enter(current);
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
ReenterI(current, &node);
node.wait_reenter_end(this);
}
// current has reacquired the lock.
// Lifecycle - the node representing current must not appear on any queues.
// Node is about to go out-of-scope, but even if it were immortal we wouldn't
// want residual elements associated with this thread left on any lists.
guarantee(node.TState == ObjectWaiter::TS_RUN, "invariant");
assert(owner_raw() == current, "invariant");
assert(_succ != current, "invariant");
} // OSThreadWaitState()
current->set_current_waiting_monitor(NULL);
guarantee(_recursions == 0, "invariant");
_recursions = save // restore the old recursion count
+ JvmtiDeferredUpdates::get_and_reset_relock_count_after_wait(current); // increased by the deferred relock count
_waiters--; // decrement the number of waiters
// Verify a few postconditions
assert(owner_raw() == current, "invariant");
assert(_succ != current, "invariant");
assert(object()->mark() == markWord::encode(this), "invariant");
// check if the notification happened
if (!WasNotified) {
// no, it could be timeout or Thread.interrupt() or both
// check for interrupt event, otherwise it is timeout
if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
THROW(vmSymbols::java_lang_InterruptedException());
}
}
// NOTE: Spurious wake up will be consider as timeout.
// Monitor notify has precedence over thread interrupt.
}
wait:
Thread 20 "Thread-0" hit Breakpoint 2, __pthread_cond_wait (cond=0x7ffff0510058, mutex=0x7ffff0510030) at forward.c:121
121 forward.c: No such file or directory.
(gdb) bt
#0 __pthread_cond_wait (cond=0x7ffff0510058, mutex=0x7ffff0510030) at forward.c:121
#1 0x00007ffff6c21713 in os::PlatformEvent::park (this=0x7ffff0510000) at /home/ubuntu/daixiao/jdk/src/hotspot/os/posix/os_posix.cpp:1484
#2 0x00007ffff6bd003c in ObjectMonitor::wait (this=0x7fffac0013b0, millis=0, interruptible=true, __the_thread__=0x7ffff050f5b0) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/objectMonitor.cpp:1544
#3 0x00007ffff6e90188 in ObjectSynchronizer::wait (obj=..., millis=0, __the_thread__=0x7ffff050f5b0) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/synchronizer.cpp:654
#4 0x00007ffff68298ae in JVM_MonitorWait (env=0x7ffff050f8a8, handle=0x7fffd0df77c0, ms=0) at /home/ubuntu/daixiao/jdk/src/hotspot/share/prims/jvm.cpp:617
#5 0x00007fffe100f68b in ?? ()
#6 0x00000008f7c32db8 in ?? ()
#7 0x00007ffff050f5b0 in ?? ()
#8 0x00007fffd0df7760 in ?? ()
#9 0x00007fffd0df7748 in ?? ()
#10 0x0000000000000000 in ?? ()
notify:
(gdb) bt
#0 __pthread_cond_signal (cond=0x7ffff04f0958) at forward.c:110
#1 0x00007ffff6c21c13 in os::PlatformEvent::unpark (this=0x7ffff04f0900) at /home/ubuntu/daixiao/jdk/src/hotspot/os/posix/os_posix.cpp:1590
#2 0x00007ffff6bcf654 in ObjectMonitor::ExitEpilog (this=0x7fffac0010b0, current=0x7ffff04ef410, Wakee=0x0) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/objectMonitor.cpp:1350
#3 0x00007ffff6bcf57b in ObjectMonitor::exit (this=0x7fffac0010b0, current=0x7ffff04ef410, not_suspended=true) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/objectMonitor.cpp:1321
#4 0x00007ffff6bcfe8e in ObjectMonitor::wait (this=0x7fffac0010b0, millis=0, interruptible=true, __the_thread__=0x7ffff04ef410) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/objectMonitor.cpp:1515
#5 0x00007ffff6e90188 in ObjectSynchronizer::wait (obj=..., millis=0, __the_thread__=0x7ffff04ef410) at /home/ubuntu/daixiao/jdk/src/hotspot/share/runtime/synchronizer.cpp:654
#6 0x00007ffff68298ae in JVM_MonitorWait (env=0x7ffff04ef708, handle=0x7fffd0df77c0, ms=0) at /home/ubuntu/daixiao/jdk/src/hotspot/share/prims/jvm.cpp:617
#7 0x00007fffe100f68b in ?? ()
#8 0x00000008f7c32db8 in ?? ()
#9 0x00007ffff04ef410 in ?? ()
#10 0x00007fffd0df7760 in ?? ()
#11 0x00007fffd0df7748 in ?? ()
#12 0x0000000000000000 in ?? ()
void PlatformEvent::park() { // AKA "down()"
// Transitions for _event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _event to 0 before returning
// Invariant: Only the thread associated with the PlatformEvent
// may call park().
assert(_nParked == 0, "invariant");
int v;
// atomically decrement _event
for (;;) {
v = _event;
if (Atomic::cmpxchg(&_event, v, v - 1) == v) break;
}
guarantee(v >= 0, "invariant");
if (v == 0) { // Do this the hard way by blocking ...
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
guarantee(_nParked == 0, "invariant");
++_nParked;
while (_event < 0) {
// OS-level "spurious wakeups" are ignored
status = pthread_cond_wait(_cond, _mutex);
assert_status(status == 0 MACOS_ONLY(|| status == ETIMEDOUT),
status, "cond_wait");
}
--_nParked;
_event = 0;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other.
OrderAccess::fence();
}
guarantee(_event >= 0, "invariant");
}
demo
#include <stdio.h>
#include <pthread.h>
#include<unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int condition = 0;
int count = 0;
pthread_t thread_id;
int consume( void )
{
while( 1 )
{
pthread_mutex_lock( &mutex );
while( condition == 0 )
pthread_cond_wait( &cond, &mutex );
printf( "Consumed %d\n", count );
condition = 0;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
}
return( 0 );
}
void* produce( void * arg )
{
while( 1 )
{
pthread_mutex_lock( &mutex );
while( condition == 1 )
pthread_cond_wait( &cond, &mutex );
printf( "Produced %d\n", count++ );
condition = 1;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
}
return( 0 );
}
int main( void )
{
pthread_create( thread_id, NULL, &produce, NULL );
return consume();
}
例子
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int num = 0;
int main(){
int error = pthread_mutex_lock( &mutex);
if(error){
perror(strerror(error));
exit(0);
}
while(num <= 0){
error = pthread_cond_wait( &cond, &mutex);
if(error){
perror(strerror(error));
exit(0);
}
}
pthread_mutex_unlock(&mutex);
return 0;
}
相关阅读
- https://stackoverflow.com/questions/54265523/how-is-java-wait-waiting-implemented
- https://blog.csdn.net/b_x_p/article/details/103980515
- https://cxyzjd.com/article/qq_26222859/53930941
- https://lotabout.me/books/Java-Concurrency/Thread-Pool/Shutdown.html
- 线程退出
- safepoint
- 条件变量
- lock
- pthread_cond_signal 是否加lock
- 相关阅读
basic paxos
basic paxos
目的:
basic paxos 目的是为了让多个副本最多只有一个值.
paxos make simple
有一篇论文,描述了basic paxos 的证明和推导过程,描述了prepare 过程的原理
p1 每个acceptor必须有接收第一个它收到的proposal
p2 当一个proposal的value 被chosen , 那么所有后续proposal 的值等于value
p2a 当一个proposal的value 被chosen , 那么后续所有acceptor接收的值等于value
p2b 当一个proposal的value被chosen , 那么后续所有proposer issue 的proposal number 对应的值等于value
p2c 对应数字n 和值v , 当acceptor 有一个最大集合S ,这个集合满足其中一个条件: 1 没有accetor 一个大于n的值 2 issue 的v 等于这个最大集合S中proposal number 最大的值
要满足p2c:
条件1 容易判断 ,
条件2: 怎么保证是小于n的最大值呢?
通过prepare 语句: 在集合S的accetor不会接受比n小的issue , 这样,当前的集合中的最大的就是被accept中小于n的最大的 proposal number
每个guarantee的原因
P1: 为了保证只有一个proposal也能chose a value
P2: 为了保证多个被chosen的proposal 都有同样的值(We can allow multiple proposals to be chosen, but we must guarantee
that all chosen proposals have the same value)
P2a: 为了满足p2 , 我们给出当被chosen的时候,所有acceptor都具有被chosen的value
P2b:为了满足p2a,我们给出,当被chosen的时候,所有issue的值都有被chseon的value
P2c:
- 大前提
assume that some proposal with number m and value
v is chosen and show that any proposal issued with number n > m also
has value v
- 小前提
assumption that every proposal issued with a number in m . . (n − 1) has
value v , where i . . j denotes the set of numbers from i through j
相关阅读: