Java 多線程基礎(六)線程等待與喚醒

 Java 多線程基礎(六)線程等待與喚醒

遇到這樣一個場景,當某線程裏面的邏輯需要等待異步處理結果返回后才能繼續執行。或者說想要把一個異步的操作封裝成一個同步的過程。這裏就用到了線程等待喚醒機制。

wait()、notify()、notifyAll() 等方法介紹

在 Object 中,定義了 wait()、notify() 和 notifyAll() 等接口。wait() 的作用是讓當前線程進入等待狀態,同時,wait() 也會讓當前線程釋放它所持有的鎖。而 notify() 和 notifyAll() 的作用,則是喚醒當前對象上的等待線程;notify() 是喚醒單個線程,而 notifyAll() 是喚醒所有的線程。

Object類中關於等待/喚醒的API詳細信息如下:

notify()                                       — 喚醒在此對象監視器上等待的單個線程。
notifyAll()                                  — 喚醒在此對象監視器上等待的所有線程。
wait()                                         — 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法”,當前線程被喚醒(進入“就緒狀態”)。
wait(long timeout)                    — 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量”,當前線程被喚醒(進入“就緒狀態”)。
wait(long timeout, int nanos)  — 讓當前線程處於“等待(阻塞)狀態”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量”,當前線程被喚醒(進入“就緒狀態”)。

二、wait() 和 notify() 示例

public class Demo02 {
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");
        synchronized (t1) {
            try {
                // 啟動“線程t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();
                // 主線程等待t1通過notify()喚醒。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();
                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        synchronized (this) {
            try {
                System.out.println(Thread.currentThread().getName()+" call notify()");
                notify(); // 喚醒當前的Demo02線程
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
}
// 運行結果
main start t1
main wait()
t1 call notify()
main continue

說明:

①、 注意,圖中”主線程” 代表“主線程main”。”線程t1″ 代表Demo02中啟動的“線程t1”。 而“鎖” 代表“t1這個對象的同步鎖”。
②、“主線程”通過 new ThreadA(“t1”) 新建“線程t1”。隨後通過synchronized(t1)獲取“t1對象的同步鎖”。然後調用t1.start()啟動“線程t1”。
③、“主線程”執行t1.wait() 釋放“t1對象的鎖”並且進入“等待(阻塞)狀態”。等待t1對象上的線程通過notify() 或 notifyAll()將其喚醒。
④、“線程t1”運行之後,通過synchronized(this)獲取“當前對象的鎖”;接着調用notify()喚醒“當前對象上的等待線程”,也就是喚醒“主線程”。
⑤、“線程t1”運行完畢之後,釋放“當前對象的鎖”。緊接着,“主線程”獲取“t1對象的鎖”,然後接着運行。

具體過程圖解

三、wait(long timeout) 和 notify()

public class Demo02 {
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");

        synchronized(t1) {
            try {
                // 啟動線程t1
                System.out.println(Thread.currentThread().getName() + " start t1");
                t1.start();

                // 主線程等待t1通過notify()喚醒 或 notifyAll()喚醒,或超過3s延時;然後才被喚醒。
                System.out.println(Thread.currentThread().getName() + " call wait ");
                t1.wait(3000);

                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run ");
        // 死循環,不斷運行。
        while(true)
            ;
    }
}
// 運行結果
main start t1
main call wait 
t1 run             // 3秒后輸出 main continue
main continue 

 說明:

如下圖,說明了“主線程”和“線程t1”的流程。
①、注意,圖中”主線程” 代表線程main。”線程t1″ 代表MyThread中啟動的線程t1。 而“鎖” 代表“t1這個對象的同步鎖”。
②、主線程main執行t1.start()啟動“線程t1”。
③、主線程main執行t1.wait(3000),此時,主線程進入“阻塞狀態”。需要“用於t1對象鎖的線程通過notify() 或者 notifyAll()將其喚醒” 或者 “超時3000ms之後”,主線程main才進入到“就緒狀態”,然後才可以運行。
④、“線程t1”運行之後,進入了死循環,一直不斷的運行。
⑤、超時3000ms之後,主線程main會進入到“就緒狀態”,然後接着進入“運行狀態”。

 具體過程圖解:

四、wait() 和 notifyAll()

public class Demo02 {
    private static Object obj = new Object();
    public static void main(String[] args) {
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        MyThread t3 = new MyThread("t3");
        t1.start();
        t2.start();
        t3.start();
        try {
            System.out.println(Thread.currentThread().getName()+" sleep(5000)");
            Thread.sleep(5000); // 休眠5秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (obj) {
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
        
    }
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            synchronized (obj) { 
                try {
                    System.out.println(Thread.currentThread().getName() + " run ");
                    obj.wait();
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
// 運行結果
t1 run 
t2 run 
main sleep(5000)
t3 run 
main notifyAll()
t3 continue
t2 continue
t1 continue

說明:

①、 主線程中新建並且啟動了3個線程”t1″, “t2″和”t3″。
②、主線程通過sleep(5000)休眠5秒。在主線程休眠3秒的過程中,我們假設”t1″, “t2″和”t3″這3個線程都運行了。以”t1″為例,當它運行的時候,它會執行obj.wait()等待其它線程通過notify()或nofityAll()來喚醒它;相同的道理,”t2″和”t3″也會等待其它線程通過nofity()或nofityAll()來喚醒它們。
③、主線程休眠3秒之後,接着運行。執行 obj.notifyAll() 喚醒obj上的等待線程,即喚醒”t1″, “t2″和”t3″這3個線程。 緊接着,主線程的synchronized(obj)運行完畢之後,主線程釋放“obj鎖”。這樣,”t1”, “t2″和”t3″就可以獲取“obj鎖”而繼續運行了!

具體過程圖解

五、 為什麼notify(), wait()等函數定義在Object中,而不是Thread中

Object中的wait(), notify()等函數,和synchronized一樣,會對“對象的同步鎖”進行操作。

wait()會使“當前線程”等待,因為線程進入等待狀態,所以線程應該釋放它鎖持有的“同步鎖”,否則其它線程獲取不到該“同步鎖”而無法運行!
OK,線程調用wait()之後,會釋放它鎖持有的“同步鎖”;而且,根據前面的介紹,我們知道:等待線程可以被notify()或notifyAll()喚醒。現在,請思考一個問題:notify()是依據什麼喚醒等待線程的?或者說,wait()等待線程和notify()之間是通過什麼關聯起來的?答案是:依據“對象的同步鎖”。

負責喚醒等待線程的那個線程(我們稱為“喚醒線程”),它只有在獲取“該對象的同步鎖”(這裏的同步鎖必須和等待線程的同步鎖是同一個),並且調用notify()或notifyAll()方法之後,才能喚醒等待線程。雖然,等待線程被喚醒;但是,它不能立刻執行,因為喚醒線程還持有“該對象的同步鎖”。必須等到喚醒線程釋放了“對象的同步鎖”之後,等待線程才能獲取到“對象的同步鎖”進而繼續運行。

總之,notify(), wait()依賴於“同步鎖”,而“同步鎖”是對象鎖持有,並且每個對象有且僅有一個!這就是為什麼notify(), wait()等函數定義在Object類,而不是Thread類中的原因。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

多線程高併發編程(11) — 非阻塞算法實現ConcurrentLinkedQueue源碼分析

  一.背景

  要實現對隊列的安全訪問,有兩種方式:阻塞算法和非阻塞算法。阻塞算法的實現是使用一把鎖(出隊和入隊同一把鎖ArrayBlockingQueue)和兩把鎖(出隊和入隊各一把鎖LinkedBlockingQueue)來實現;非阻塞算法使用自旋+CAS實現。

  
阻塞,顧名思義:當我們的生產者向隊列中生產數據時,若隊列已滿,那麼生產線程會暫停下來,直到隊列中有可以存放數據的地方,才會繼續工作;而當我們的消費者向隊列中獲取數據時,若隊列為空,則消費者線程會暫停下來,直到容器中有元素出現,才能進行獲取操作。
  那麼對於非阻塞來說,非阻塞隊列的執行並不會被阻塞,無論是消費者的出隊,還是生產者的入隊。同時對於入隊和出隊,使用了向後推進策略(重新尋找頭或尾節點)保證併發的數據一致性。

  今天來探究下使用非阻塞算法來實現的線程安全隊列ConcurrentLinkedQueue,它是一個基於鏈接節點的無界線程安全隊列,採用先進先出的規則對節點進行排序,當我們添加一個元素的時候,它會添加到隊列的尾部,當我們獲取一個元素時,它會返回隊列頭部的元素。它採用了“wait-free”算法(即CAS算法)來實現。即當入隊時,插入的元素依次向後延伸,形成鏈表;而出隊時,則從鏈表的第一個元素開始獲取,依次遞增。

  ConcurrentLinkedQueue的類圖結構:

   從類圖中可以看到,ConcurrentLinkedQueue由head和tail節點組成,每個節點Node由節點元素item和指向下一個節點的引用next組成,節點與節點之間通過next關聯起來組成一張鏈表結構的隊列。

  二.源碼解析

  1. 構造方法

        private static class Node<E> {
            volatile E item;//元素
            volatile Node<E> next;//下一節點
    
            Node(E item) {//添加元素
                UNSAFE.putObject(this, itemOffset, item);
            }
    
            boolean casItem(E cmp, E val) {//cas修改元素
                return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
            }
    
            void lazySetNext(Node<E> val) {//添加節點
                UNSAFE.putOrderedObject(this, nextOffset, val);
            }
    
            boolean casNext(Node<E> cmp, Node<E> val) {//cas修改節點
                return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
            }
    
            private static final sun.misc.Unsafe UNSAFE;
            private static final long itemOffset;
            private static final long nextOffset;
    
            static {
                try {
                    UNSAFE = sun.misc.Unsafe.getUnsafe();
                    Class<?> k = Node.class;
                    //獲得元素的偏移位置
                    itemOffset = UNSAFE.objectFieldOffset
                        (k.getDeclaredField("item"));
                    //獲得下一節點的偏移位置
                    nextOffset = UNSAFE.objectFieldOffset
                        (k.getDeclaredField("next"));
                } catch (Exception e) {
                    throw new Error(e);
                }
            }
        }
        //頭節點
        private transient volatile Node<E> head;
        //尾節點
        private transient volatile Node<E> tail;
        public ConcurrentLinkedQueue() {
            //默認情況下head節點存儲的元素為空,tail節點等於head節點。
            head = tail = new Node<E>(null);
        }
        public ConcurrentLinkedQueue(Collection<? extends E> c) {
            Node<E> h = null, t = null;
            //遍歷集合
            for (E e : c) {
                checkNotNull(e);//檢查是否為空,如果為空拋出空指針異常
                //創建節點和將元素存儲到節點中
                Node<E> newNode = new Node<E>(e);
                if (h == null)//頭節點為空
                    h = t = newNode;//頭和尾節點是創建的節點
                else {
                    t.lazySetNext(newNode);//添加節點
                    t = newNode;//修改尾節點的標識
                }
            }
            //如果集合沒有元素,設置隊列的頭尾節點為空
            if (h == null)
                h = t = new Node<E>(null);
            head = h;//更新隊列的頭節點標識
            tail = t;//更新隊列的尾節點標識
        }
        private static void checkNotNull(Object v) {
            if (v == null)
                throw new NullPointerException();
        }    
  2. 入隊add:

    • 入隊操作主要做兩件事情,第一是將入隊節點設置成當前隊列尾節點的下一個節點;第二是更新tail節點,如果tail節點的next節點不為空,則將入隊節點設置成tail節點,如果tail節點的next節點為空,則將入隊節點設置成tail的next節點,所以tail節點不總是尾節點

    • 上面的分析讓我們從單線程入隊的角度來理解入隊過程,但是多個線程同時進行入隊情況就變得更加複雜,因為可能會出現其他線程插隊的情況。如果有一個線程正在入隊,那麼它必須先獲取尾節點,然後設置尾節點的下一個節點為入隊節點,但這時可能有另外一個線程插隊了,那麼隊列的尾節點就會發生變化,這時當前線程要暫停入隊操作,然後重新獲取尾節點。

    • 源碼解析:從下面可以看出,入隊永遠是返回true,所以不要通過返回值判斷是否入隊成功

      public boolean add(E e) {
              return offer(e);
          }
          public boolean offer(E e) {
              checkNotNull(e);//檢查是否為空
              //創建入隊節點,將元素添加到節點中
              final Node<E> newNode = new Node<E>(e);
              //自旋隊列CAS直到入隊成功
              // 1、根據tail節點定位出尾節點(last node);2、將新節點置為尾節點的下一個節點;3、casTail更新尾節點
              for (Node<E> t = tail, p = t;;) {
                  //p是尾節點,q得到尾節點的next
                  Node<E> q = p.next;
                  //如果q為空
                  if (q == null) {
                      //p是last node,將尾節點的next修改為創建的節點
                      if (p.casNext(null, newNode)) {
                          //p在遍歷後會變化,因此需要判斷,如果不相等即p != t = tail,表示t(= tail)不是尾節點,則將入隊節點設置成tail節點,更新失敗了也沒關係,因為失敗了表示有其他線程成功更新了tail節點
                          if (p != t)
                              casTail(t, newNode);//入隊節點更新為尾節點,允許失敗,因此t= tail並不總是尾節點
                          return true;//結束
                      }
                  }
                  //重新獲取head節點:多線程操作時,輪詢后p有可能等於q,此時,就需要對p重新賦值
                  //(多線程自引用的情況,只有offer()和poll()交替執行時會出現)
                  else if (p == q)
                      //因為併發下可能tail被改了,如果被改了,則使用新的t,否則跳轉到head,從鏈表頭重新輪詢,因為從head開始所有的節點都可達
                      p = (t != (t = tail)) ? t : head;//運行到這裏再繼續自旋遍歷
                  else
                      /**
                       * 尋找尾節點,同樣,當t不等於p時,說明p在上面被重新賦值了,並且tail也被別的線程改了,則使用新的tail,否則循環檢查p的下個節點
                       *  (多offer()情況下會出現)
                       * p=condition?result1:result2
                       *  滿足result1的場景為 :
                       *      獲取尾節點tail的快照已經過時了(其他線程更新了新的尾節點tail),直接跳轉到當前獲得的最新尾節點的地方
                       *  滿足result2的場景為:
                       *      多線程同時操作offer(),執行p.casNext(null, newNode)CAS成功后,未更新尾節點(未執行casTail(t, newNode)方法:兩種原因 1是未滿足前置條件if判斷 2是CAS更新失敗),直接找next節點
                       */
                      p = (p != t && t != (t = tail)) ? t : q;//運行到這裏再繼續自旋遍歷
              }
          }
    1. debug斷點測試案例:

      public static void main(String[] args) throws IndexOutOfBoundsException {
              ConcurrentLinkedQueue c = new ConcurrentLinkedQueue();
              new Thread(()->{
                  int i;
                  for(i=0;i<10;){
                      c.offer(i++);
                      Object poll = c.poll();//註釋或取消進行測試
                      System.out.println(Thread.currentThread().getName()+":"+poll);
                  }
              }).start();
              new Thread(()->{
                  int i;
                  for(i=200;i<210;){
                      c.offer(i++);
                      Object poll = c.poll();//註釋或取消進行測試
                      System.out.println(Thread.currentThread().getName()+":"+poll);
                  }
              }).start();
           }
    2. tail多線程的更新情況:通過p和t是否相等來判斷

  3. 出隊poll:

    • 從上圖可知,並不是每次出隊時都更新head節點,當head節點里有元素時,直接彈出head節點里的元素,而不會更新head節點。只有當head節點里沒有元素時,出隊操作才會更新head節點。採用這種方式也是為了減少使用CAS更新head節點的消耗,從而提高出隊效率。
    • 源碼解析:

      public E poll() {
              restartFromHead:
              //自旋
              for (;;) {
                  //獲得頭節點
                  for (Node<E> h = head, p = h, q;;) {
                      E item = p.item;//獲得頭節點元素
                      //如果頭節點元素不為null並且cas刪除頭節點元素成功
                      if (item != null && p.casItem(item, null)) {
                          //p被修改了
                          if (p != h) // hop two nodes at a time
                              // 如果p 的next 屬性不是null ,將 p 作為頭節點,而 q 將會消失
                              updateHead(h, ((q = p.next) != null) ? q : p);
                          return item;
                      }
                      //如果頭節點的元素為空或頭節點發生了變化,這說明頭節點已經被另外一個線程修改了。
                      // 那麼獲取p節點的下一個節點,如果p節點的下一節點為null,則表明隊列已經空了
                      // 如果 p(head) 的 next 節點 q 也是null,則表示沒有數據了,返回null,則將 head 設置為null
                      // 注意:updateHead 方法最後還會將原有的 head 作為自己 next 節點,方便offer 連接。
                      else if ((q = p.next) == null) {
                          updateHead(h, p);
                          return null;
                      }
                      //如果 p == q,說明別的線程取出了 head,並將 head 更新了。就需要重新開始獲取head節點
                      else if (p == q)
                          continue restartFromHead;
                      // 如果下一個元素不為空,則將頭節點的下一個節點設置成頭節點
                      else
                          p = q;
                  }
              }
          }
          final void updateHead(Node<E> h, Node<E> p) {
              if (h != p && casHead(h, p))
                  // 將舊的頭結點h的next域指向為h
                  h.lazySetNext(h);
          }
  4. 入隊和出隊操作中,都有p == q的情況,在下面這種情況中:

    • 在彈出一個節點之後,tail節點有一條指向自己的虛線,這是什麼意思呢?在poll()方法中,移除元素之後,會調用updateHead方法,其中有h.lazySetNext(h),可以看到,在更新完head之後,會將舊的頭結點h的next域指向為h,上圖中所示的虛線也就表示這個節點的自引用
    • 如果這時,再有一個線程來添加元素,通過tail獲取的next節點則仍然是它本身,這就出現了p == q的情況,出現該種情況之後,則會觸發執行head的更新,將p節點重新指向為head,所有“活着”的節點(指未刪除節點),都能從head通過遍歷可達,這樣就能通過head成功獲取到尾節點,然後添加元素了。

  5. 獲取首部元素peek:

    • 從圖中可以看到,peek操作會改變head指向,執行peek()方法后head會指向第一個具有非空元素的節點。
    • 源碼解析:
      // 獲取鏈表的首部元素(只讀取而不移除)
          public E peek() {
              restartFromHead:
              //自旋
              for (;;) {
                  for (Node<E> h = head, p = h, q;;) {
                      //獲得頭節點元素
                      E item = p.item;
                      //頭節點元素不為空或頭節點下一節點為空(表示鏈表只有一個節點)
                      if (item != null || (q = p.next) == null) {
                          updateHead(h, p);//更新頭節點標識
                          return item;
                      }
                      /如果 p == q,說明別的線程取出了 head,並將 head 更新了。就需要重新開始獲取head節點
                      else if (p == q)
                          continue restartFromHead;
                      // 如果下一個元素不為空,則將頭節點的下一個節點設置成頭節點
                      else
                          p = q;
                  }
              }
          }
  6. 判斷隊列是否為空isEmpty:

        public boolean isEmpty() {
                return first() == null;
        }
        Node<E> first() {
            restartFromHead:
            for (;;) {
                for (Node<E> h = head, p = h, q;;) {
                    //頭節點是否有元素
                    boolean hasItem = (p.item != null);
                    //頭節點有元素或當前鏈表只有一個節點
                    if (hasItem || (q = p.next) == null) {
                        updateHead(h, p);
                        return hasItem ? p : null;//頭節點有值返回節點,否則返回null
                    }
                    else if (p == q)
                        continue restartFromHead;
                    else
                        p = q;
                }
            }
        }
  7. 獲取個數size:在併發環境中,其結果可能不精確,因為整個過程都沒有加鎖,所以從調用size方法到返回結果期間有可能增刪元素,導致統計的元素個數不精確。【在隊列元素很多的時候,size()方法十分消耗性能和時間,只是單純的判斷隊列為空使用isEmpty()即可!!!】

        public int size() {
            int count = 0;
            // first()獲取第一個具有非空元素的節點,若不存在,返回null
            // succ(p)方法獲取p的後繼節點,若p == p的後繼節點,則返回head
            for (Node<E> p = first(); p != null; p = succ(p))
                //節點有元素數量+1
                if (p.item != null)
                    if (++count == Integer.MAX_VALUE)
                        break;
            return count;
        }
        //取下一節點
        final Node<E> succ(Node<E> p) {
            Node<E> next = p.next;
            //若p == p的後繼節點(自引用情況下會出現),則返回head
            return (p == next) ? head : next;
        }
    • 探討:為何 ConcurrentLinkedQueue 中需要遍歷鏈表來獲取 size 而不適用一個原子變量呢?

      • 這是因為使用原子變量保存隊列元素個數需要保證入隊出隊操作和操作原子變量是原子操作,而ConcurrentLinkedQueue 是使用 CAS 無鎖算法的,所以無法做到這個。
  8. 判斷元素是否包含contains:該方法和size方法類似,有可能返回錯誤結果,比如調用該方法時,元素還在隊列裏面,但是遍歷過程中,該元素被刪除了,那麼就會返回false。

        public boolean contains(Object o) {
            if (o == null) return false;
            for (Node<E> p = first(); p != null; p = succ(p)) {
                E item = p.item;
                // 若找到匹配節點,則返回true
                if (item != null && o.equals(item))
                    return true;
            }
            return false;
        }
  9. 刪除元素remove:

        public boolean remove(Object o) {
            //刪除的元素不能為null,
            if (o != null) {
                Node<E> next, pred = null;
                //遍歷,開始獲得頭節點,
                for (Node<E> p = first(); p != null; pred = p, p = next) {
                    boolean removed = false;//刪除的標識
                    E item = p.item;//節點元素
                    if (item != null) {
                        //節點的元素不等於要刪除的元素,獲取下一節點進行遍歷循環操作
                        if (!o.equals(item)) {
                            next = succ(p);//將當前遍歷的節點移到下一節點
                            continue;
                        }
                        //節點元素等於刪除元素,CAS將節點元素置為null
                        removed = p.casItem(item, null);
                    }
                    next = succ(p);//獲取刪除節點的下一節點,
                    //有前節點和後置節點
                    if (pred != null && next != null) // unlink
                        pred.casNext(p, next);//刪除當前節點,即當前節點移除出隊列
                    if (removed)//元素刪除了返回true
                        return true;
                }
            }
            return false;
        }

  三.總結

  • 使用 CAS 原子指令來處理對數據的併發訪問,這是非阻塞算法得以實現的基礎。
  • head/tail 並非總是指向隊列的頭 / 尾節點,也就是說允許隊列處於不一致狀態。 這個特性把入隊 / 出隊時,原本需要一起原子化執行的兩個步驟分離開來,從而縮小了入隊 / 出隊時需要原子化更新值的範圍到唯一變量。這是非阻塞算法得以實現的關鍵。
  • 由於隊列有時會處於不一致狀態。為此,ConcurrentLinkedQueue 使用三個不變式來維護非阻塞算法的正確性。
  • 以批處理方式來更新 head/tail,從整體上減少入隊 / 出隊操作的開銷。
  • 為了有利於垃圾收集,隊列使用特有的 head 更新機制;為了確保從已刪除節點向後遍歷,可到達所有的非刪除節點,隊列使用了特有的向後推進策略。

  四.參考

  • https://blog.csdn.net/qq_38293564/article/details/80798310
  • https://www.ibm.com/developerworks/cn/java/j-lo-concurrent/index.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

[apue] 一個快速確定新系統上各類限制值的工具

對於在不同 Unix 系統之間移植程序,最重要的事情就是確定新系統的一些編譯時、運行時固定或不固定的限制值了。例如文件路徑最大長度 PATH_MAX、進程最大可打開文件句柄數 OPEN_MAX、用戶可加入的附加用戶組最大數量 NGROUPS_MAX、進程命令行參數最大字節數 ARG_MAX、內存頁大小 PAGESIZE、線程棧大小默認值 STACKSIZE、臨時文件最大數量 TMP_MAX 等等。甚至有些系統特徵也可以通過查詢來提前確定,例如是否支持讀寫鎖、是否支持異步 IO、是否支持實時信號等等,這樣程序就可以根據系統提供的能力來選擇不同的接口去實現同樣的功能。

回頭來看 apue 第二章有關係統限制與選項這一塊的內容,由於摻雜了 UNIX 標準化的內容,顯得很沒有條理,例如將各種限制按標準劃分為:

  • ISO C
    • 編譯時限制 (頭文件常量)
  • POSIX
    • 不變的最小值 (聲明遵循 POSIX 的系統必需支持到至少這麼多,不能再小了)
    • 不變值 (SSIZE_MAX)
    • 運行時可增加的值
    • 運行時不變的值
    • 路徑名可變值
  • XSI
    • 不變的最小值 (同上)
    • 數值限制
    • 運行時不變值

看得人一頭霧水,其實如果拋開標準,單按限制的性質來分,就比較簡單啦:

  • 編譯時限制 (通過頭文件常量)
  • 運行時限制
    • 不與文件系統相關部分(通過 sysconf)
    • 與文件系統相關部分(通過 pathconf)

也就是說,要確定一個系統限制,一共分兩步:

  1. 確定相應的符號常量有沒有在頭文件定義,如果有,直接拿來用;
  2. 如果沒有,走 sysconf 或 pathconf 查詢。

對於系統選項,稍等複雜一點,分三步:

  1. 符號常量定義為 -1,平台不支持該選項;
  2. 符號常量定義大於 0,平台支持相應的選項;
  3. 符號常量定義為 0,需要進一步依靠 sysconf 或 pathconf 來查詢。

到這裏,你大概已經想到怎麼自己製作一個工具了,那就是按上面的邏輯 coding 唄,可以把想要查的常量作為輸入,查到的結果打印到控制台,就像下面這樣:

conf.c

 1 #include "../apue.h" 
 2 #include <errno.h>
 3 #include <limits.h> 
 4 
 5 static void pr_sysconf (char*, int); 
 6 static void pr_pathconf (char *, char *, int); 
 7 
 8 int 
 9 main (int argc, char *argv[])
10 {
11   if (argc != 2)
12     err_quit ("usage: conf <dirname>"); 
13 
14 #ifdef _POSIX_OPEN_MAX
15   printf ("_POSIX_OPEN_MAX defined to be %d\n", _POSIX_OPEN_MAX); 
16 #else 
17   printf ("no symbol for _POSIX_OPEN_MAX\n"); 
18 #endif 
19 
20 #ifdef OPEN_MAX
21   printf ("OPEN_MAX defined to be %d\n", OPEN_MAX); 
22 #else 
23   printf ("no symbol for OPEN_MAX\n"); 
24 #endif 
25 
26 #ifdef _SC_OPEN_MAX
27   pr_sysconf ("sysconf (_SC_OPEN_MAX) = ", _SC_OPEN_MAX); 
28 #else 
29   printf ("no symbol for _SC_OPEN_MAX\n"); 
30 #endif 
31 
32 #ifdef _POSIX_NAME_MAX
33   printf ("_POSIX_NAME_MAX defined to be %d\n", _POSIX_NAME_MAX); 
34 #else 
35   printf ("no symbol for _POSIX_NAME_MAX\n"); 
36 #endif 
37 
38 #ifdef NAME_MAX
39   printf ("NAME_MAX defined to be %d\n", NAME_MAX); 
40 #else 
41   printf ("no symbol for NAME_MAX\n"); 
42 #endif 
43 
44 #ifdef _PC_NAME_MAX
45   pr_pathconf ("pathconf (_PC_NAME_MAX) = ", argv[1], _PC_NAME_MAX); 
46 #else 
47   printf ("no symbol for _PC_NAME_MAX\n"); 
48 #endif 
49 
50   exit (0); 
51 }
52 
53 static void 
54 pr_sysconf (char *msg, int name) 
55 {
56   long val; 
57   fputs (msg, stdout); 
58   errno = 0; 
59   if ((val = sysconf (name)) < 0) { 
60     if (errno != 0) { 
61       if (errno == EINVAL)
62         fputs ("(not supported)\n", stdout); 
63       else 
64         err_sys ("sysconf error"); 
65     }
66     else
67       fputs ("(no limit)\n", stdout); 
68   }
69   else
70     printf ("%ld\n", val); 
71 }
72 
73 
74 static void 
75 pr_pathconf (char *msg, char *path, int name) 
76 {
77   long val; 
78   fputs (msg, stdout); 
79   errno = 0; 
80   if ((val = pathconf (path, name)) < 0) { 
81     if (errno != 0) { 
82       if (errno == EINVAL)
83         fputs ("(not supported)\n", stdout); 
84       else 
85         err_sys ("pathconf error, path = %s", path); 
86     }
87     else
88       fputs ("(no limit)\n", stdout); 
89   }
90   else
91     printf ("%ld\n", val); 
92 }

 

這個程序處理了兩個常量: OPEN_MAX 與 NAME_MAX,對於每個常量,它都嘗試檢測  _POSIX_XXX 是否存在,不同點在於,前者不依賴於文件系統,所以最後調用 sysconf 檢測;後者依賴文件系統,所以調用 pathconf 檢測。至於為何在 pr_sysconf / pr_pathconf 中清理 errno,可以參考我之前寫過的一篇文章:[apue] sysconf 的四種返回狀態 。這個程序要求一個路徑,可以這樣輸入參數來使之工作:

$ ./conf /
_POSIX_OPEN_MAX defined to be 20
no symbol for OPEN_MAX
sysconf (_SC_OPEN_MAX) = 1024
_POSIX_NAME_MAX defined to be 14
NAME_MAX defined to be 255
pathconf (_PC_NAME_MAX) = 255

 

為方便工具靈活的處理各種不同輸入,之樣直接寫死常量肯定是不靈活了,有的同學已經想到了將常量作為命令行參數傳入,這個辦法也可以。不過這裏借鑒書上一種使用 awk 自動生成 c 代碼的方法,將上面的例子 awk 化:

conf.awk

  1 #! /bin/awk -f
  2 BEGIN {
  3 printf("#define _GNU_SOURCE  \n")
  4 printf("#include \"../apue.h\" \n")
  5 printf("#include <errno.h>\n")
  6 printf("#include <limits.h> \n")
  7 printf("#include <sys/param.h> \n")
  8 printf("\n")
  9 printf("static void pr_sysconf (char*, int); \n")
 10 printf("static void pr_pathconf (char *, char *, int); \n")
 11 printf("\n")
 12 printf("int \n")
 13 printf("main (int argc, char *argv[])\n")
 14 printf("{\n")
 15 printf("  if (argc != 2)\n")
 16 printf("    err_quit (\"usage: conf <dirname>\"); \n")
 17 printf("\n")
 18 FS=":"
 19 while (getline < "sysconf.sym" > 0) {
 20 printf("#ifdef %s\n", $1)
 21 printf("  printf (\"%s defined to be %%d\\n\", %s+0); \n", $1, $1)
 22 printf("#else \n")
 23 printf("  printf (\"no symbol for %s\\n\"); \n", $1)
 24 printf("#endif \n")
 25 printf("\n")
 26 printf("#ifdef _%s\n", $1)
 27 printf("  printf (\"_%s defined to be %%d\\n\", _%s+0); \n", $1, $1)
 28 printf("#else \n")
 29 printf("  printf (\"no symbol for _%s\\n\"); \n", $1)
 30 printf("#endif \n")
 31 printf("\n")
 32 printf("#ifdef _POSIX_%s\n", $1)
 33 printf("  printf (\"_POSIX_%s defined to be %%d\\n\", _POSIX_%s+0); \n", $1, $1)
 34 printf("#else \n")
 35 printf("  printf (\"no symbol for _POSIX_%s\\n\"); \n", $1)
 36 printf("#endif \n")
 37 printf("\n")
 38 printf("#ifdef P%s\n", $1)
 39 printf("  printf (\"P%s defined to be %%d\\n\", P%s+0); \n", $1, $1)
 40 printf("#else \n")
 41 printf("  printf (\"no symbol for P%s\\n\"); \n", $1)
 42 printf("#endif \n")
 43 printf("\n")
 44 printf("#ifdef _SC_%s\n", $1)
 45 printf("  pr_sysconf (\"sysconf (_SC_%s) = \", _SC_%s); \n", $1, $1)
 46 printf("#else \n")
 47 printf("  printf (\"no symbol for _SC_%s\\n\"); \n", $1)
 48 printf("#endif \n")
 49 printf("printf (\"\\n\"); \n")
 50 printf("\n")
 51 }
 52 close ("sysconf.sym")
 53 while (getline < "pathconf.sym" > 0) {
 54 printf("#ifdef %s\n", $1)
 55 printf("  printf (\"%s defined to be %%d\\n\", %s+0); \n", $1, $1)
 56 printf("#else \n")
 57 printf("  printf (\"no symbol for %s\\n\"); \n", $1)
 58 printf("#endif \n")
 59 printf("\n")
 60 printf("#ifdef _%s\n", $1)
 61 printf("  printf (\"_%s defined to be %%d\\n\", _%s+0); \n", $1, $1)
 62 printf("#else \n")
 63 printf("  printf (\"no symbol for _%s\\n\"); \n", $1)
 64 printf("#endif \n")
 65 printf("\n")
 66 printf("#ifdef _POSIX_%s\n", $1)
 67 printf("  printf (\"_POSIX_%s defined to be %%d\\n\", _POSIX_%s+0); \n", $1, $1)
 68 printf("#else \n")
 69 printf("  printf (\"no symbol for _POSIX_%s\\n\"); \n", $1)
 70 printf("#endif \n")
 71 printf("\n")
 72 printf("#ifdef _PC_%s\n", $1)
 73 printf("  pr_pathconf (\"pathconf (_PC_%s) = \", argv[1], _PC_%s); \n", $1, $1)
 74 printf("#else \n")
 75 printf("  printf (\"no symbol for _PC_%s\\n\"); \n", $1)
 76 printf("#endif \n")
 77 printf("printf (\"\\n\"); \n")
 78 printf("\n")
 79 }
 80 close ("pathconf.sym"); 
 81 exit
 82 }
 83 END {
 84 printf("  exit (0); \n")
 85 printf("}\n")
 86 printf("\n")
 87 printf("static void \n")
 88 printf("pr_sysconf (char *msg, int name) \n")
 89 printf("{\n")
 90 printf("  long val; \n")
 91 printf("  fputs (msg, stdout); \n")
 92 printf("  errno = 0; \n")
 93 printf("  if ((val = sysconf (name)) < 0) { \n")
 94 printf("    if (errno != 0) { \n")
 95 printf("      if (errno == EINVAL)\n")
 96 printf("        fputs (\"(not supported)\\n\", stdout); \n")
 97 printf("      else \n")
 98 printf("        err_sys (\"sysconf error\"); \n")
 99 printf("    }\n")
100 printf("    else\n")
101 printf("      fputs (\"(no limit)\\n\", stdout); \n")
102 printf("  }\n")
103 printf("  else\n")
104 printf("    printf (\"%%ld\\n\", val); \n")
105 printf("}\n")
106 printf("\n")
107 printf("\n")
108 printf("static void \n")
109 printf("pr_pathconf (char *msg, char *path, int name) \n")
110 printf("{\n")
111 printf("  long val; \n")
112 printf("  fputs (msg, stdout); \n")
113 printf("  errno = 0; \n")
114 printf("  if ((val = pathconf (path, name)) < 0) { \n")
115 printf("    if (errno != 0) { \n")
116 printf("      if (errno == EINVAL)\n")
117 printf("        fputs (\"(not supported)\\n\", stdout); \n")
118 printf("      else \n")
119 printf("        err_sys (\"pathconf error, path = %%s\", path); \n")
120 printf("    }\n")
121 printf("    else\n")
122 printf("      fputs (\"(no limit)\\n\", stdout); \n")
123 printf("  }\n")
124 printf("  else\n")
125 printf("    printf (\"%%ld\\n\", val); \n")
126 printf("}\n")
127 }

 

其實原理很簡單啦,就是把每一行都用 awk printf 來生成,只是針對常量部分,使用一個循環,分別從文件中讀取常量來進行動態生成。這裏需要提供兩個文件: sysconf.sym 與 pathconf.sym,分別對應不依賴文件系統的常量與依賴文件系統的常量,因為最後它們的調用方法不同,之前已經說明過了。

sysconf.sym

ARG_MAX
ATEXIT_MAX
CHILD_MAX
CLK_TCK
CLOCKS_PER_SEC
HOST_NAME_MAX
IOV_MAX
LOGIN_NAME_MAX
NGROUPS_MAX
OPEN_MAX
PAGESIZE
PAGE_SIZE
RE_DUP_MAX
STREAM_MAX
SYMLOOP_MAX
TTY_NAME_MAX
TZNAME_MAX
BC_BASE_MAX
BC_DIM_MAX
BC_SCALE_MAX
BC_STRING_MAX
COLL_WEIGHTS_MAX
EXPR_NEST_MAX
LINE_MAX
POSIX_VERSION
POSIX_SOURCE
POSIX_C_SOURCE
POSIX2_VERSION
POSIX2_C_DEV
POSIX2_FORT_DEV
POSIX2_FORT_RUN
POSIX2_LOCALEDEF
POSIX2_SW_DEV
POSIX_PHYS_PAGES
POSIX_AVPHYS_PAGES
V6_ILP32_OFF32
V6_ILP32_OFFBIG
V6_LP64_OFF64
V6_LP64_OFFBIG
SSIZE_MAX
CHARCLASS_NAME_MAX
FOPEN_MAX
TMP_MAX
LONG_BIT
WORD_BIT
NL_ARGMAX
NL_LANGMAX
LANGMAX
NL_MSGMAX
MSGMAX
NL_NMAX
NMAX
NL_SETMAX
SETMAX
NL_TEXTMAX
TEXTMAX
NZERO
NOFILE
NFILE
JOB_CONTROL
READER_WRITER_LOCKS
SAVED_IDS
SHELL
VERSION
GETPW_R_SIZE_MAX
GETGR_R_SIZE_MAX
PASS_MAX
THREAD_DESTRUCTOR_ITERATIONS
THREAD_KEYS_MAX
THREAD_STACK_MIN
THREAD_THREADS_MAX
THREAD_SAFE_FUNCTIONS
ADVISORY_INFO
ASYNCHRONOUS_IO
BARRIERS
CPUTIME
CLOCK_SELECTION
FSYNC
IPV6
MAPPED_FILES
MEMLOCK
MEMLOCK_RANGE
MONOTONIC_CLOCK
MEMORY_PROTECTION
MESSAGE_PASSING
PRIORITIZED_IO
PRIORITIZED_SCHEDULING
RAW_SOCKETS
REALTIME_SIGNALS
SEMAPHORES
SHARED_MEMORY_OBJECTS
SYNCHRONIZED_IO
SPIN_LOCKS
SPAWN
SPORADIC_SERVER
THREAD_CPUTIME
TRACE
TRACE_INHERIT
TRACE_LOG
TRACE_EVENT_FILTER
THREADS
THREAD_PRIO_INHERIT
THREAD_PRIO_PROTECT
THREAD_PRIORITY_SCHEDULING
THREAD_ATTR_STACKADDR
THREAD_SAFE_FUNCTIONS
THREAD_PROCESS_SHARED
THREAD_SPORADIC_SERVER
THREAD_ATTR_STACKSIZE
TYPED_MEMORY_OBJECTS
XOPEN_SOURCE
XOPEN_UNIX
XOPEN_STREAMS
XOPEN_CRYPE
XOPEN_REALTIME
XOPEN_REALTIME_THREADS
XOPEN_LEGACY
XOPEN_VERSION
XOPEN_IOV_MAX
XOPEN_NAME_MAX
XOPEN_PATH_MAX
FILENAME_MAX
__STD_C__
_STRICT_ANSI_
_ISOC99_SOURCE
_BSD_SOURCE
_SVID_SOURCE
_GNU_SOURCE

 

pathconf.sym

FILESIZEBITS
LINK_MAX
MAX_CANON
MAX_INPUT
NAME_MAX
PATH_MAX
PIPE_BUF
SYMLINK_MAX
CHOWN_RESTRICTED
NO_TRUNC
VDISABLE

 

與書上不同,這裏沒有讓用戶分別提供常量的各個名稱,以 OPEN_MAX 為例,書上的 sym 文件內容是 ”OPEN_MAX    _PC_OPEN_MAX“ 為一行內容,分別指定常量的編譯期名稱與運行期查詢名稱。這裏感覺有些啰嗦,直接讓用戶提供一個原始名稱 OPEN_MAX,然後我在 awk 腳本里做了一些處理,去拼接生成各種名稱。例如還以 OPEN_MAX 為例,它會嘗試以下名稱:

  • OPEN_MAX  (原名稱)
  • _OPEN_MAX  (_XXX)
  • _POSIX_OPEN_MAX  (_POSIX_XXX)
  • POPEN_MAX  (PXXX)
  • _PC_OPEN_MAX  (_PC_XXX)

主要起作用的規則是第 1 個與第 3 個,第 2 個規則對於形如 XOPEN_UNIX 的常量有用 (同時存在 _XOPEN_UNIX 與 _PC_XOPEN_UNIX);第 4 個規則對於形如  THREAD_KEYS_MAX 的常量有用 (同時存在 _POSIX_THREAD_KEYS_MAX / PTHREAD_KEYS_MAX / _PC_THREAD_KEYS_MAX);最後一個規則對於 pathconf.sym 而言是 _PC_XXX。

有了這個代碼模板和常量定義文件之後,就可以通過 Makefile 將它們串在一起啦:

Makefile

 1 all: conf
 2 
 3 conf: conf.o apue.o
 4     gcc -Wall -g $^ -o $@
 5 
 6 conf.o: conf.c ../apue.h
 7     gcc -Wall -g -c $< -o $@
 8 
 9 conf.c: conf.awk sysconf.sym pathconf.sym
10     ./$^ > $@
11 
12 apue.o: ../apue.c ../apue.h 
13     gcc -Wall -g -c $< -o $@
14 
15 clean: 
16     @echo "start clean..."
17     -rm -f *.o core.* *.log *~ *.swp conf conf.c
18     @echo "end clean"
19 
20 .PHONY: clean

 

這樣每次修改 sym 文件后,直接 make 就可以將新的常量包含進去了。下面是運行效果:

[yunhai@localhost 01.chapter]$ ./conf /
no symbol for ARG_MAX
no symbol for _ARG_MAX
_POSIX_ARG_MAX defined to be 4096
no symbol for PARG_MAX
sysconf (_SC_ARG_MAX) = 2621440

no symbol for ATEXIT_MAX
no symbol for _ATEXIT_MAX
no symbol for _POSIX_ATEXIT_MAX
no symbol for PATEXIT_MAX
sysconf (_SC_ATEXIT_MAX) = 2147483647

no symbol for CHILD_MAX
no symbol for _CHILD_MAX
_POSIX_CHILD_MAX defined to be 25
no symbol for PCHILD_MAX
sysconf (_SC_CHILD_MAX) = 1024

no symbol for CLK_TCK
no symbol for _CLK_TCK
no symbol for _POSIX_CLK_TCK
no symbol for PCLK_TCK
sysconf (_SC_CLK_TCK) = 100

no symbol for CLOCKS_PER_SEC
no symbol for _CLOCKS_PER_SEC
no symbol for _POSIX_CLOCKS_PER_SEC
no symbol for PCLOCKS_PER_SEC
no symbol for _SC_CLOCKS_PER_SEC

HOST_NAME_MAX defined to be 64
no symbol for _HOST_NAME_MAX
_POSIX_HOST_NAME_MAX defined to be 255
no symbol for PHOST_NAME_MAX
sysconf (_SC_HOST_NAME_MAX) = 64

IOV_MAX defined to be 1024
no symbol for _IOV_MAX
no symbol for _POSIX_IOV_MAX
no symbol for PIOV_MAX
sysconf (_SC_IOV_MAX) = 1024

LOGIN_NAME_MAX defined to be 256
no symbol for _LOGIN_NAME_MAX
_POSIX_LOGIN_NAME_MAX defined to be 9
no symbol for PLOGIN_NAME_MAX
sysconf (_SC_LOGIN_NAME_MAX) = 256

NGROUPS_MAX defined to be 65536
no symbol for _NGROUPS_MAX
_POSIX_NGROUPS_MAX defined to be 8
no symbol for PNGROUPS_MAX
sysconf (_SC_NGROUPS_MAX) = 65536

no symbol for OPEN_MAX
no symbol for _OPEN_MAX
_POSIX_OPEN_MAX defined to be 20
no symbol for POPEN_MAX
sysconf (_SC_OPEN_MAX) = 1024

no symbol for PAGESIZE
no symbol for _PAGESIZE
no symbol for _POSIX_PAGESIZE
no symbol for PPAGESIZE
sysconf (_SC_PAGESIZE) = 4096

no symbol for PAGE_SIZE
no symbol for _PAGE_SIZE
no symbol for _POSIX_PAGE_SIZE
no symbol for PPAGE_SIZE
sysconf (_SC_PAGE_SIZE) = 4096

RE_DUP_MAX defined to be 32767
no symbol for _RE_DUP_MAX
_POSIX_RE_DUP_MAX defined to be 255
no symbol for PRE_DUP_MAX
sysconf (_SC_RE_DUP_MAX) = 32767

no symbol for STREAM_MAX
no symbol for _STREAM_MAX
_POSIX_STREAM_MAX defined to be 8
no symbol for PSTREAM_MAX
sysconf (_SC_STREAM_MAX) = 16

no symbol for SYMLOOP_MAX
no symbol for _SYMLOOP_MAX
_POSIX_SYMLOOP_MAX defined to be 8
no symbol for PSYMLOOP_MAX
sysconf (_SC_SYMLOOP_MAX) = (no limit)

TTY_NAME_MAX defined to be 32
no symbol for _TTY_NAME_MAX
_POSIX_TTY_NAME_MAX defined to be 9
no symbol for PTTY_NAME_MAX
sysconf (_SC_TTY_NAME_MAX) = 32

no symbol for TZNAME_MAX
no symbol for _TZNAME_MAX
_POSIX_TZNAME_MAX defined to be 6
no symbol for PTZNAME_MAX
sysconf (_SC_TZNAME_MAX) = 6

BC_BASE_MAX defined to be 99
no symbol for _BC_BASE_MAX
no symbol for _POSIX_BC_BASE_MAX
no symbol for PBC_BASE_MAX
sysconf (_SC_BC_BASE_MAX) = 99

BC_DIM_MAX defined to be 2048
no symbol for _BC_DIM_MAX
no symbol for _POSIX_BC_DIM_MAX
no symbol for PBC_DIM_MAX
sysconf (_SC_BC_DIM_MAX) = 2048

BC_SCALE_MAX defined to be 99
no symbol for _BC_SCALE_MAX
no symbol for _POSIX_BC_SCALE_MAX
no symbol for PBC_SCALE_MAX
sysconf (_SC_BC_SCALE_MAX) = 99

BC_STRING_MAX defined to be 1000
no symbol for _BC_STRING_MAX
no symbol for _POSIX_BC_STRING_MAX
no symbol for PBC_STRING_MAX
sysconf (_SC_BC_STRING_MAX) = 1000

COLL_WEIGHTS_MAX defined to be 255
no symbol for _COLL_WEIGHTS_MAX
no symbol for _POSIX_COLL_WEIGHTS_MAX
no symbol for PCOLL_WEIGHTS_MAX
sysconf (_SC_COLL_WEIGHTS_MAX) = 255

EXPR_NEST_MAX defined to be 32
no symbol for _EXPR_NEST_MAX
no symbol for _POSIX_EXPR_NEST_MAX
no symbol for PEXPR_NEST_MAX
sysconf (_SC_EXPR_NEST_MAX) = 32

LINE_MAX defined to be 2048
no symbol for _LINE_MAX
no symbol for _POSIX_LINE_MAX
no symbol for PLINE_MAX
sysconf (_SC_LINE_MAX) = 2048

no symbol for POSIX_VERSION
_POSIX_VERSION defined to be 200809
no symbol for _POSIX_POSIX_VERSION
no symbol for PPOSIX_VERSION
no symbol for _SC_POSIX_VERSION

no symbol for POSIX_SOURCE
_POSIX_SOURCE defined to be 1
no symbol for _POSIX_POSIX_SOURCE
no symbol for PPOSIX_SOURCE
no symbol for _SC_POSIX_SOURCE

no symbol for POSIX_C_SOURCE
_POSIX_C_SOURCE defined to be 200809
no symbol for _POSIX_POSIX_C_SOURCE
no symbol for PPOSIX_C_SOURCE
no symbol for _SC_POSIX_C_SOURCE

no symbol for POSIX2_VERSION
_POSIX2_VERSION defined to be 200809
no symbol for _POSIX_POSIX2_VERSION
no symbol for PPOSIX2_VERSION
no symbol for _SC_POSIX2_VERSION

no symbol for POSIX2_C_DEV
_POSIX2_C_DEV defined to be 200809
no symbol for _POSIX_POSIX2_C_DEV
no symbol for PPOSIX2_C_DEV
no symbol for _SC_POSIX2_C_DEV

no symbol for POSIX2_FORT_DEV
no symbol for _POSIX2_FORT_DEV
no symbol for _POSIX_POSIX2_FORT_DEV
no symbol for PPOSIX2_FORT_DEV
no symbol for _SC_POSIX2_FORT_DEV

no symbol for POSIX2_FORT_RUN
no symbol for _POSIX2_FORT_RUN
no symbol for _POSIX_POSIX2_FORT_RUN
no symbol for PPOSIX2_FORT_RUN
no symbol for _SC_POSIX2_FORT_RUN

no symbol for POSIX2_LOCALEDEF
_POSIX2_LOCALEDEF defined to be 200809
no symbol for _POSIX_POSIX2_LOCALEDEF
no symbol for PPOSIX2_LOCALEDEF
no symbol for _SC_POSIX2_LOCALEDEF

no symbol for POSIX2_SW_DEV
_POSIX2_SW_DEV defined to be 200809
no symbol for _POSIX_POSIX2_SW_DEV
no symbol for PPOSIX2_SW_DEV
no symbol for _SC_POSIX2_SW_DEV

no symbol for POSIX_PHYS_PAGES
no symbol for _POSIX_PHYS_PAGES
no symbol for _POSIX_POSIX_PHYS_PAGES
no symbol for PPOSIX_PHYS_PAGES
no symbol for _SC_POSIX_PHYS_PAGES

no symbol for POSIX_AVPHYS_PAGES
no symbol for _POSIX_AVPHYS_PAGES
no symbol for _POSIX_POSIX_AVPHYS_PAGES
no symbol for PPOSIX_AVPHYS_PAGES
no symbol for _SC_POSIX_AVPHYS_PAGES

no symbol for V6_ILP32_OFF32
no symbol for _V6_ILP32_OFF32
_POSIX_V6_ILP32_OFF32 defined to be 1
no symbol for PV6_ILP32_OFF32
sysconf (_SC_V6_ILP32_OFF32) = 1

no symbol for V6_ILP32_OFFBIG
no symbol for _V6_ILP32_OFFBIG
_POSIX_V6_ILP32_OFFBIG defined to be 1
no symbol for PV6_ILP32_OFFBIG
sysconf (_SC_V6_ILP32_OFFBIG) = 1

no symbol for V6_LP64_OFF64
no symbol for _V6_LP64_OFF64
no symbol for _POSIX_V6_LP64_OFF64
no symbol for PV6_LP64_OFF64
sysconf (_SC_V6_LP64_OFF64) = (no limit)

no symbol for V6_LP64_OFFBIG
no symbol for _V6_LP64_OFFBIG
no symbol for _POSIX_V6_LP64_OFFBIG
no symbol for PV6_LP64_OFFBIG
no symbol for _SC_V6_LP64_OFFBIG

SSIZE_MAX defined to be 2147483647
no symbol for _SSIZE_MAX
_POSIX_SSIZE_MAX defined to be 32767
no symbol for PSSIZE_MAX
sysconf (_SC_SSIZE_MAX) = 32767

CHARCLASS_NAME_MAX defined to be 2048
no symbol for _CHARCLASS_NAME_MAX
no symbol for _POSIX_CHARCLASS_NAME_MAX
no symbol for PCHARCLASS_NAME_MAX
sysconf (_SC_CHARCLASS_NAME_MAX) = 2048

FOPEN_MAX defined to be 16
no symbol for _FOPEN_MAX
no symbol for _POSIX_FOPEN_MAX
no symbol for PFOPEN_MAX
no symbol for _SC_FOPEN_MAX

TMP_MAX defined to be 238328
no symbol for _TMP_MAX
no symbol for _POSIX_TMP_MAX
no symbol for PTMP_MAX
no symbol for _SC_TMP_MAX

LONG_BIT defined to be 32
no symbol for _LONG_BIT
no symbol for _POSIX_LONG_BIT
no symbol for PLONG_BIT
sysconf (_SC_LONG_BIT) = 32

WORD_BIT defined to be 32
no symbol for _WORD_BIT
no symbol for _POSIX_WORD_BIT
no symbol for PWORD_BIT
sysconf (_SC_WORD_BIT) = 32

NL_ARGMAX defined to be 4096
no symbol for _NL_ARGMAX
no symbol for _POSIX_NL_ARGMAX
no symbol for PNL_ARGMAX
sysconf (_SC_NL_ARGMAX) = 4096

NL_LANGMAX defined to be 2048
no symbol for _NL_LANGMAX
no symbol for _POSIX_NL_LANGMAX
no symbol for PNL_LANGMAX
sysconf (_SC_NL_LANGMAX) = 2048

no symbol for LANGMAX
no symbol for _LANGMAX
no symbol for _POSIX_LANGMAX
no symbol for PLANGMAX
no symbol for _SC_LANGMAX

NL_MSGMAX defined to be 2147483647
no symbol for _NL_MSGMAX
no symbol for _POSIX_NL_MSGMAX
no symbol for PNL_MSGMAX
sysconf (_SC_NL_MSGMAX) = 2147483647

no symbol for MSGMAX
no symbol for _MSGMAX
no symbol for _POSIX_MSGMAX
no symbol for PMSGMAX
no symbol for _SC_MSGMAX

NL_NMAX defined to be 2147483647
no symbol for _NL_NMAX
no symbol for _POSIX_NL_NMAX
no symbol for PNL_NMAX
sysconf (_SC_NL_NMAX) = 2147483647

no symbol for NMAX
no symbol for _NMAX
no symbol for _POSIX_NMAX
no symbol for PNMAX
no symbol for _SC_NMAX

NL_SETMAX defined to be 2147483647
no symbol for _NL_SETMAX
no symbol for _POSIX_NL_SETMAX
no symbol for PNL_SETMAX
sysconf (_SC_NL_SETMAX) = 2147483647

no symbol for SETMAX
no symbol for _SETMAX
no symbol for _POSIX_SETMAX
no symbol for PSETMAX
no symbol for _SC_SETMAX

NL_TEXTMAX defined to be 2147483647
no symbol for _NL_TEXTMAX
no symbol for _POSIX_NL_TEXTMAX
no symbol for PNL_TEXTMAX
sysconf (_SC_NL_TEXTMAX) = 2147483647

no symbol for TEXTMAX
no symbol for _TEXTMAX
no symbol for _POSIX_TEXTMAX
no symbol for PTEXTMAX
no symbol for _SC_TEXTMAX

NZERO defined to be 20
no symbol for _NZERO
no symbol for _POSIX_NZERO
no symbol for PNZERO
sysconf (_SC_NZERO) = 20

NOFILE defined to be 256
no symbol for _NOFILE
no symbol for _POSIX_NOFILE
no symbol for PNOFILE
no symbol for _SC_NOFILE

no symbol for NFILE
no symbol for _NFILE
no symbol for _POSIX_NFILE
no symbol for PNFILE
no symbol for _SC_NFILE

no symbol for JOB_CONTROL
no symbol for _JOB_CONTROL
_POSIX_JOB_CONTROL defined to be 1
no symbol for PJOB_CONTROL
sysconf (_SC_JOB_CONTROL) = 1

no symbol for READER_WRITER_LOCKS
no symbol for _READER_WRITER_LOCKS
_POSIX_READER_WRITER_LOCKS defined to be 200809
no symbol for PREADER_WRITER_LOCKS
sysconf (_SC_READER_WRITER_LOCKS) = 200809

no symbol for SAVED_IDS
no symbol for _SAVED_IDS
_POSIX_SAVED_IDS defined to be 1
no symbol for PSAVED_IDS
sysconf (_SC_SAVED_IDS) = 1

no symbol for SHELL
no symbol for _SHELL
_POSIX_SHELL defined to be 1
no symbol for PSHELL
sysconf (_SC_SHELL) = 1

no symbol for VERSION
no symbol for _VERSION
_POSIX_VERSION defined to be 200809
no symbol for PVERSION
sysconf (_SC_VERSION) = 200809

no symbol for GETPW_R_SIZE_MAX
no symbol for _GETPW_R_SIZE_MAX
no symbol for _POSIX_GETPW_R_SIZE_MAX
no symbol for PGETPW_R_SIZE_MAX
sysconf (_SC_GETPW_R_SIZE_MAX) = 1024

no symbol for GETGR_R_SIZE_MAX
no symbol for _GETGR_R_SIZE_MAX
no symbol for _POSIX_GETGR_R_SIZE_MAX
no symbol for PGETGR_R_SIZE_MAX
sysconf (_SC_GETGR_R_SIZE_MAX) = 1024

no symbol for PASS_MAX
no symbol for _PASS_MAX
no symbol for _POSIX_PASS_MAX
no symbol for PPASS_MAX
sysconf (_SC_PASS_MAX) = 8192

no symbol for THREAD_DESTRUCTOR_ITERATIONS
no symbol for _THREAD_DESTRUCTOR_ITERATIONS
_POSIX_THREAD_DESTRUCTOR_ITERATIONS defined to be 4
PTHREAD_DESTRUCTOR_ITERATIONS defined to be 4
sysconf (_SC_THREAD_DESTRUCTOR_ITERATIONS) = 4

no symbol for THREAD_KEYS_MAX
no symbol for _THREAD_KEYS_MAX
_POSIX_THREAD_KEYS_MAX defined to be 128
PTHREAD_KEYS_MAX defined to be 1024
sysconf (_SC_THREAD_KEYS_MAX) = 1024

no symbol for THREAD_STACK_MIN
no symbol for _THREAD_STACK_MIN
no symbol for _POSIX_THREAD_STACK_MIN
PTHREAD_STACK_MIN defined to be 16384
sysconf (_SC_THREAD_STACK_MIN) = 16384

no symbol for THREAD_THREADS_MAX
no symbol for _THREAD_THREADS_MAX
_POSIX_THREAD_THREADS_MAX defined to be 64
no symbol for PTHREAD_THREADS_MAX
sysconf (_SC_THREAD_THREADS_MAX) = (no limit)

no symbol for THREAD_SAFE_FUNCTIONS
no symbol for _THREAD_SAFE_FUNCTIONS
_POSIX_THREAD_SAFE_FUNCTIONS defined to be 200809
no symbol for PTHREAD_SAFE_FUNCTIONS
sysconf (_SC_THREAD_SAFE_FUNCTIONS) = 200809

no symbol for ADVISORY_INFO
no symbol for _ADVISORY_INFO
_POSIX_ADVISORY_INFO defined to be 200809
no symbol for PADVISORY_INFO
sysconf (_SC_ADVISORY_INFO) = 200809

no symbol for ASYNCHRONOUS_IO
no symbol for _ASYNCHRONOUS_IO
_POSIX_ASYNCHRONOUS_IO defined to be 200809
no symbol for PASYNCHRONOUS_IO
sysconf (_SC_ASYNCHRONOUS_IO) = 200809

no symbol for BARRIERS
no symbol for _BARRIERS
_POSIX_BARRIERS defined to be 200809
no symbol for PBARRIERS
sysconf (_SC_BARRIERS) = 200809

no symbol for CPUTIME
no symbol for _CPUTIME
_POSIX_CPUTIME defined to be 0
no symbol for PCPUTIME
sysconf (_SC_CPUTIME) = 200809

no symbol for CLOCK_SELECTION
no symbol for _CLOCK_SELECTION
_POSIX_CLOCK_SELECTION defined to be 200809
no symbol for PCLOCK_SELECTION
sysconf (_SC_CLOCK_SELECTION) = 200809

no symbol for FSYNC
no symbol for _FSYNC
_POSIX_FSYNC defined to be 200809
no symbol for PFSYNC
sysconf (_SC_FSYNC) = 200809

no symbol for IPV6
no symbol for _IPV6
_POSIX_IPV6 defined to be 200809
no symbol for PIPV6
sysconf (_SC_IPV6) = 200809

no symbol for MAPPED_FILES
no symbol for _MAPPED_FILES
_POSIX_MAPPED_FILES defined to be 200809
no symbol for PMAPPED_FILES
sysconf (_SC_MAPPED_FILES) = 200809

no symbol for MEMLOCK
no symbol for _MEMLOCK
_POSIX_MEMLOCK defined to be 200809
no symbol for PMEMLOCK
sysconf (_SC_MEMLOCK) = 200809

no symbol for MEMLOCK_RANGE
no symbol for _MEMLOCK_RANGE
_POSIX_MEMLOCK_RANGE defined to be 200809
no symbol for PMEMLOCK_RANGE
sysconf (_SC_MEMLOCK_RANGE) = 200809

no symbol for MONOTONIC_CLOCK
no symbol for _MONOTONIC_CLOCK
_POSIX_MONOTONIC_CLOCK defined to be 0
no symbol for PMONOTONIC_CLOCK
sysconf (_SC_MONOTONIC_CLOCK) = 200809

no symbol for MEMORY_PROTECTION
no symbol for _MEMORY_PROTECTION
_POSIX_MEMORY_PROTECTION defined to be 200809
no symbol for PMEMORY_PROTECTION
sysconf (_SC_MEMORY_PROTECTION) = 200809

no symbol for MESSAGE_PASSING
no symbol for _MESSAGE_PASSING
_POSIX_MESSAGE_PASSING defined to be 200809
no symbol for PMESSAGE_PASSING
sysconf (_SC_MESSAGE_PASSING) = 200809

no symbol for PRIORITIZED_IO
no symbol for _PRIORITIZED_IO
_POSIX_PRIORITIZED_IO defined to be 200809
no symbol for PPRIORITIZED_IO
sysconf (_SC_PRIORITIZED_IO) = 200809

no symbol for PRIORITIZED_SCHEDULING
no symbol for _PRIORITIZED_SCHEDULING
no symbol for _POSIX_PRIORITIZED_SCHEDULING
no symbol for PPRIORITIZED_SCHEDULING
no symbol for _SC_PRIORITIZED_SCHEDULING

no symbol for RAW_SOCKETS
no symbol for _RAW_SOCKETS
_POSIX_RAW_SOCKETS defined to be 200809
no symbol for PRAW_SOCKETS
sysconf (_SC_RAW_SOCKETS) = 200809

no symbol for REALTIME_SIGNALS
no symbol for _REALTIME_SIGNALS
_POSIX_REALTIME_SIGNALS defined to be 200809
no symbol for PREALTIME_SIGNALS
sysconf (_SC_REALTIME_SIGNALS) = 200809

no symbol for SEMAPHORES
no symbol for _SEMAPHORES
_POSIX_SEMAPHORES defined to be 200809
no symbol for PSEMAPHORES
sysconf (_SC_SEMAPHORES) = 200809

no symbol for SHARED_MEMORY_OBJECTS
no symbol for _SHARED_MEMORY_OBJECTS
_POSIX_SHARED_MEMORY_OBJECTS defined to be 200809
no symbol for PSHARED_MEMORY_OBJECTS
sysconf (_SC_SHARED_MEMORY_OBJECTS) = 200809

no symbol for SYNCHRONIZED_IO
no symbol for _SYNCHRONIZED_IO
_POSIX_SYNCHRONIZED_IO defined to be 200809
no symbol for PSYNCHRONIZED_IO
sysconf (_SC_SYNCHRONIZED_IO) = 200809

no symbol for SPIN_LOCKS
no symbol for _SPIN_LOCKS
_POSIX_SPIN_LOCKS defined to be 200809
no symbol for PSPIN_LOCKS
sysconf (_SC_SPIN_LOCKS) = 200809

no symbol for SPAWN
no symbol for _SPAWN
_POSIX_SPAWN defined to be 200809
no symbol for PSPAWN
sysconf (_SC_SPAWN) = 200809

no symbol for SPORADIC_SERVER
no symbol for _SPORADIC_SERVER
_POSIX_SPORADIC_SERVER defined to be -1
no symbol for PSPORADIC_SERVER
sysconf (_SC_SPORADIC_SERVER) = (no limit)

no symbol for THREAD_CPUTIME
no symbol for _THREAD_CPUTIME
_POSIX_THREAD_CPUTIME defined to be 0
no symbol for PTHREAD_CPUTIME
sysconf (_SC_THREAD_CPUTIME) = 200809

no symbol for TRACE
no symbol for _TRACE
_POSIX_TRACE defined to be -1
no symbol for PTRACE
sysconf (_SC_TRACE) = (no limit)

no symbol for TRACE_INHERIT
no symbol for _TRACE_INHERIT
_POSIX_TRACE_INHERIT defined to be -1
no symbol for PTRACE_INHERIT
sysconf (_SC_TRACE_INHERIT) = (no limit)

no symbol for TRACE_LOG
no symbol for _TRACE_LOG
_POSIX_TRACE_LOG defined to be -1
no symbol for PTRACE_LOG
sysconf (_SC_TRACE_LOG) = (no limit)

no symbol for TRACE_EVENT_FILTER
no symbol for _TRACE_EVENT_FILTER
_POSIX_TRACE_EVENT_FILTER defined to be -1
no symbol for PTRACE_EVENT_FILTER
sysconf (_SC_TRACE_EVENT_FILTER) = (no limit)

no symbol for THREADS
no symbol for _THREADS
_POSIX_THREADS defined to be 200809
no symbol for PTHREADS
sysconf (_SC_THREADS) = 200809

no symbol for THREAD_PRIO_INHERIT
no symbol for _THREAD_PRIO_INHERIT
_POSIX_THREAD_PRIO_INHERIT defined to be 200809
no symbol for PTHREAD_PRIO_INHERIT
sysconf (_SC_THREAD_PRIO_INHERIT) = 200809

no symbol for THREAD_PRIO_PROTECT
no symbol for _THREAD_PRIO_PROTECT
_POSIX_THREAD_PRIO_PROTECT defined to be 200809
no symbol for PTHREAD_PRIO_PROTECT
sysconf (_SC_THREAD_PRIO_PROTECT) = 200809

no symbol for THREAD_PRIORITY_SCHEDULING
no symbol for _THREAD_PRIORITY_SCHEDULING
_POSIX_THREAD_PRIORITY_SCHEDULING defined to be 200809
no symbol for PTHREAD_PRIORITY_SCHEDULING
sysconf (_SC_THREAD_PRIORITY_SCHEDULING) = 200809

no symbol for THREAD_ATTR_STACKADDR
no symbol for _THREAD_ATTR_STACKADDR
_POSIX_THREAD_ATTR_STACKADDR defined to be 200809
no symbol for PTHREAD_ATTR_STACKADDR
sysconf (_SC_THREAD_ATTR_STACKADDR) = 200809

no symbol for THREAD_SAFE_FUNCTIONS
no symbol for _THREAD_SAFE_FUNCTIONS
_POSIX_THREAD_SAFE_FUNCTIONS defined to be 200809
no symbol for PTHREAD_SAFE_FUNCTIONS
sysconf (_SC_THREAD_SAFE_FUNCTIONS) = 200809

no symbol for THREAD_PROCESS_SHARED
no symbol for _THREAD_PROCESS_SHARED
_POSIX_THREAD_PROCESS_SHARED defined to be 200809
no symbol for PTHREAD_PROCESS_SHARED
sysconf (_SC_THREAD_PROCESS_SHARED) = 200809

no symbol for THREAD_SPORADIC_SERVER
no symbol for _THREAD_SPORADIC_SERVER
_POSIX_THREAD_SPORADIC_SERVER defined to be -1
no symbol for PTHREAD_SPORADIC_SERVER
sysconf (_SC_THREAD_SPORADIC_SERVER) = (no limit)

no symbol for THREAD_ATTR_STACKSIZE
no symbol for _THREAD_ATTR_STACKSIZE
_POSIX_THREAD_ATTR_STACKSIZE defined to be 200809
no symbol for PTHREAD_ATTR_STACKSIZE
sysconf (_SC_THREAD_ATTR_STACKSIZE) = 200809

no symbol for TYPED_MEMORY_OBJECTS
no symbol for _TYPED_MEMORY_OBJECTS
_POSIX_TYPED_MEMORY_OBJECTS defined to be -1
no symbol for PTYPED_MEMORY_OBJECTS
sysconf (_SC_TYPED_MEMORY_OBJECTS) = (no limit)

no symbol for XOPEN_SOURCE
_XOPEN_SOURCE defined to be 700
no symbol for _POSIX_XOPEN_SOURCE
no symbol for PXOPEN_SOURCE
no symbol for _SC_XOPEN_SOURCE

no symbol for XOPEN_UNIX
_XOPEN_UNIX defined to be 1
no symbol for _POSIX_XOPEN_UNIX
no symbol for PXOPEN_UNIX
sysconf (_SC_XOPEN_UNIX) = 1

no symbol for XOPEN_STREAMS
_XOPEN_STREAMS defined to be -1
no symbol for _POSIX_XOPEN_STREAMS
no symbol for PXOPEN_STREAMS
sysconf (_SC_XOPEN_STREAMS) = (no limit)

no symbol for XOPEN_CRYPE
no symbol for _XOPEN_CRYPE
no symbol for _POSIX_XOPEN_CRYPE
no symbol for PXOPEN_CRYPE
no symbol for _SC_XOPEN_CRYPE

no symbol for XOPEN_REALTIME
_XOPEN_REALTIME defined to be 1
no symbol for _POSIX_XOPEN_REALTIME
no symbol for PXOPEN_REALTIME
sysconf (_SC_XOPEN_REALTIME) = 1

no symbol for XOPEN_REALTIME_THREADS
_XOPEN_REALTIME_THREADS defined to be 1
no symbol for _POSIX_XOPEN_REALTIME_THREADS
no symbol for PXOPEN_REALTIME_THREADS
sysconf (_SC_XOPEN_REALTIME_THREADS) = 1

no symbol for XOPEN_LEGACY
_XOPEN_LEGACY defined to be 1
no symbol for _POSIX_XOPEN_LEGACY
no symbol for PXOPEN_LEGACY
sysconf (_SC_XOPEN_LEGACY) = 1

no symbol for XOPEN_VERSION
_XOPEN_VERSION defined to be 700
no symbol for _POSIX_XOPEN_VERSION
no symbol for PXOPEN_VERSION
sysconf (_SC_XOPEN_VERSION) = 700

no symbol for XOPEN_IOV_MAX
_XOPEN_IOV_MAX defined to be 16
no symbol for _POSIX_XOPEN_IOV_MAX
no symbol for PXOPEN_IOV_MAX
no symbol for _SC_XOPEN_IOV_MAX

no symbol for XOPEN_NAME_MAX
no symbol for _XOPEN_NAME_MAX
no symbol for _POSIX_XOPEN_NAME_MAX
no symbol for PXOPEN_NAME_MAX
no symbol for _SC_XOPEN_NAME_MAX

no symbol for XOPEN_PATH_MAX
no symbol for _XOPEN_PATH_MAX
no symbol for _POSIX_XOPEN_PATH_MAX
no symbol for PXOPEN_PATH_MAX
no symbol for _SC_XOPEN_PATH_MAX

FILENAME_MAX defined to be 4096
no symbol for _FILENAME_MAX
no symbol for _POSIX_FILENAME_MAX
no symbol for PFILENAME_MAX
no symbol for _SC_FILENAME_MAX

no symbol for __STD_C__
no symbol for ___STD_C__
no symbol for _POSIX___STD_C__
no symbol for P__STD_C__
no symbol for _SC___STD_C__

no symbol for _STRICT_ANSI_
no symbol for __STRICT_ANSI_
no symbol for _POSIX__STRICT_ANSI_
no symbol for P_STRICT_ANSI_
no symbol for _SC__STRICT_ANSI_

_ISOC99_SOURCE defined to be 1
no symbol for __ISOC99_SOURCE
no symbol for _POSIX__ISOC99_SOURCE
no symbol for P_ISOC99_SOURCE
no symbol for _SC__ISOC99_SOURCE

_BSD_SOURCE defined to be 1
no symbol for __BSD_SOURCE
no symbol for _POSIX__BSD_SOURCE
no symbol for P_BSD_SOURCE
no symbol for _SC__BSD_SOURCE

_SVID_SOURCE defined to be 1
no symbol for __SVID_SOURCE
no symbol for _POSIX__SVID_SOURCE
no symbol for P_SVID_SOURCE
no symbol for _SC__SVID_SOURCE

_GNU_SOURCE defined to be 0
no symbol for __GNU_SOURCE
no symbol for _POSIX__GNU_SOURCE
no symbol for P_GNU_SOURCE
no symbol for _SC__GNU_SOURCE

no symbol for FILESIZEBITS
no symbol for _FILESIZEBITS
no symbol for _POSIX_FILESIZEBITS
pathconf (_PC_FILESIZEBITS) = 64

no symbol for LINK_MAX
no symbol for _LINK_MAX
_POSIX_LINK_MAX defined to be 8
pathconf (_PC_LINK_MAX) = 32000

MAX_CANON defined to be 255
no symbol for _MAX_CANON
_POSIX_MAX_CANON defined to be 255
pathconf (_PC_MAX_CANON) = 255

MAX_INPUT defined to be 255
no symbol for _MAX_INPUT
_POSIX_MAX_INPUT defined to be 255
pathconf (_PC_MAX_INPUT) = 255

NAME_MAX defined to be 255
no symbol for _NAME_MAX
_POSIX_NAME_MAX defined to be 14
pathconf (_PC_NAME_MAX) = 255

PATH_MAX defined to be 4096
no symbol for _PATH_MAX
_POSIX_PATH_MAX defined to be 256
pathconf (_PC_PATH_MAX) = 4096

PIPE_BUF defined to be 4096
no symbol for _PIPE_BUF
_POSIX_PIPE_BUF defined to be 512
pathconf (_PC_PIPE_BUF) = 4096

no symbol for SYMLINK_MAX
no symbol for _SYMLINK_MAX
_POSIX_SYMLINK_MAX defined to be 255
pathconf (_PC_SYMLINK_MAX) = (no limit)

no symbol for CHOWN_RESTRICTED
no symbol for _CHOWN_RESTRICTED
_POSIX_CHOWN_RESTRICTED defined to be 0
pathconf (_PC_CHOWN_RESTRICTED) = 1

no symbol for NO_TRUNC
no symbol for _NO_TRUNC
_POSIX_NO_TRUNC defined to be 1
pathconf (_PC_NO_TRUNC) = 1

no symbol for VDISABLE
no symbol for _VDISABLE
_POSIX_VDISABLE defined to be 0
pathconf (_PC_VDISABLE) = 0

 

我運行的環境是 CentOS 6.7,通過 grep 去掉沒有定義的常量 (grep -v ‘no symbol’) 之後,和在另一台機器上 (NeoKylin)上的運行結果做個對比,如下:

 

其中 CentOS 是 32 位,而中標麒麟是 64 位。不過好像也看不出來什麼很大的差異,而且有些限制通過這樣的查詢也不一定準確,例如最大打開文件句柄數,很可能就和 ulimit 設置相關,如果想找到確切的限制值的話,建議還是使用 getrlimit 去獲取,會更準確一些。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

Enevate推出電動車5分鐘極速快充電池技術

  鋰離子(Li-ion)電池技術公司Enevate Corporation宣布為電動車(EV)推出HD-Energy技術,僅僅5分鐘高能量密度的極速快充可將行駛里程增加多達390公里,充電60秒行駛里程可增加最多達80公里。這一快速充電技術所帶來的極短的充電時間優於目前所有其他鋰離子電池技術,同時滿足汽車對能量密度、里程和成本的進一步要求。Enevate計劃將其以矽為主材的HD-Energy技術授權給全球的電池和電動車製造商及供應商。   這一創新的極速快充技術打破了電動車普及的重重壁壘。一直以來,由於有限的行駛里程所導致的駕駛「里程焦慮」、充電時間過長以及高成本等原因,電動車始終難以普及。如今, Enevate應用於鎳鈷錳(NCM)電動車電池的突破性矽鋰離子電池技術經測試已可用高達10C的充電速率在5分鐘內充電至75%的電池容量且不會影響到電池的使用壽命。同時,其超過750Wh/L的能量密度不會在行駛里程上打折扣。而傳統石墨電池在極速快充中會出現電池急劇退化的問題。   該5分鐘充電技術讓流通出入型充電站的應用成為可能,電動車駕駛人僅需等待幾分鐘即可完成「充電」,就像出入普通加油站一樣。此外,由於充電時間極短,一些電動車中可以選擇使用更小型的電池,使電動車更加多樣化並且經濟適用。   公司創始人兼首席技術官Benjamin Park博士表示:「Enevate以矽為主材的HD-Energy技術具備的優勢可實現新一代功能,將電動車推向全新水平。該技術支持極速快充,可在很短時間便捷地進行充電,具備有助於延長駕駛里程的更高能量密度,同時具備低溫操作的固有安全優勢,這些使其成為電動車電池的理想之選。」   Enevate的HD-Energy電池技術可在低至零下40°C的溫度下實現安全充放電,並且可在再生煞車期間捕獲更多的能量,從而延長了在寒冷氣候中的行駛里程。Enevate HD-Energy技術具備一個關鍵的內在安全優勢,即在快速充電和在低溫充電時可防止鋰析出,這是傳統石墨鋰離子電池所面臨的一個主要挑戰。   德克薩斯大學奧斯汀分校的鋰離子電池先驅John Goodenough博士對此表示贊同,他說:「Enevate以矽為主材的薄膜陽極和電池是一種極具創新性的方法,在電動車應用中具有很大的實用價值,可有效解決電動車普及所面臨的主要障礙。」   (資訊來源:Enevate;首圖來源:Enevate)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

聚甘新

石油需求觸頂是危言聳聽?能源巨擘不怕電動車威脅

  全球環保意識高漲,歐洲和中國相繼宣布,未來將禁售汽柴油車。不少專家預測,石油需求即將觸頂,但是能源巨擘對此嗤之以鼻,深信石油需求將持續成長,對再生能源投資只有石油的九牛一毛。   路透社8日報導,二十年前英國石油公司(BP)看好再生能源,不只改換商標,還宣布要在十年內斥資80億美元發展綠能。不料此一大膽舉動慘敗收場,BP的太陽能事業被陸廠打到無力招架,美國風力發電事業更連賣都賣不掉。BP學到教訓,再次聚焦石油,其他油商也看在眼裡,對於綠能投資格外謹慎。   證據何在?路透訪調分析顯示,全球前五大油商,包括BP、Total、雪佛龍(Chevron)、艾克森美孚(Exxon Mobil)、荷蘭殼牌(Royal Dutch Shell),投資替代能源都只是輕描淡寫。Wood Mackenzie估計前五大油商每年投資的1,000億美元中,只有3%用於再生能源。雪佛龍執行長John Watson說,目前沒有石油需求觸頂的跡象,未來10~20年,石油需求將持續成長。   能源巨擘信心滿滿,是看準新興市場的石油需求將持續增加。艾克森美孚估計,2040年亞洲的運輸需求將使得燃料需求提高25%。BP也說,全球生產石油中,有1/5用於汽車,如果電動車真的奪取大量市佔,空運、鐵路、卡車運輸仍會拉高石油需求。油商也大力投資天然氣,算準就算電動車起飛,天然氣能用於發電,需求仍會成長。   (本文內容由授權使用。首圖來源:pixabay)  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司“嚨底家”!

※推薦評價好的iphone維修中心

聚甘新

中國新能源車政策鬆綁,外資獲准持有多數股權

  川普本周亞洲行來到中國,中方頻頻讓利討川普歡心。11月9日在習近平與川普的一場會談上,中國宣布訪寬外資對新能源車的持股限制,美國電動車龍頭特斯拉有望受惠。   中國目前限制外資持有合資公司的股份不得超過50%。但從明年六月起,設點在指定自貿區的電動車或其它類型的新能源車合資公司,外資持股比例將可超過五成門檻。   有意深耕中國市場的特斯拉,可能成為政策鬆綁下的潛在受惠者。華爾街日報日前報導指出,特斯拉擬赴上海設廠,且已與中國政府達成協議,雙方只差細節與宣布時間還未敲定,可能正在等待新政策發布。   另外,福特、安徽眾泰汽車(Anhui Zotye Automobile Co.)11月8日在川普的見證下,宣布兩公司將合資7.56億美元,在中國打造動車廠,雙方持股比為50:50。   (本文內容由授權使用。首圖來源:public domain CC0)  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

聚甘新

300隻稀有麗龜慘淪海上浮屍 身纏廢棄漁網無辜喪命

摘錄自2018年8月30日ETtoday報導

墨西哥漁民28日在南部海岸發現約有300隻麗龜屍體在海上載浮載沉,這些麗龜被廢棄的非法漁網困住,導致動彈不得而死亡,而且屍體已經開始腐爛。死亡的麗龜目前被埋在沙灘上,官方已經對於設網兇手展開調查。麗龜體長約75公分,重達45公斤,每年5月到9月會到墨西哥太平洋沿岸產卵,被視為瀕臨滅絕的物種。

綜合外媒報導,根據畫面顯示,許多麗龜屍體已經呈現分解的狀態,甚至有些已經碎片化。

墨西哥聯邦環境保護署(PROFEPA)發言人指出,這300隻麗龜是被困在120公尺的漁網內。麗龜體長約75公分,重達45公斤。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

聚甘新

德國風機大縣 面臨農村地景與風機權衡的綠能抉擇

環境資訊中心記者 陳文姿報導

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司“嚨底家”!

※推薦評價好的iphone維修中心

聚甘新

「孤獨海豚」!水族館關閉後 牠們獨活8個月

摘錄自2018年08月31日蘋果日報日本報導

日本千葉縣一間水族館年初時因經營不善倒閉,但媒體發現,水族館內還有大量海洋生物遭遺棄,過去8個月來雖靠著員工定時餵食存活,但狀況堪憂。尤其是館內一頭名叫「甜心」(Honey)的海豚,牠因孤獨被留在水池內而出現壓力過大現象。日本動物保育團體和網友發現後相當痛心,呼籲相關單位盡快伸出援手。

當地媒體報導,「甜心」是在2005年於太地町「血腥海灣」被捕捉後送往千葉縣銚子市的犬吠埼水族館,成為遊客的觀賞對象。該水族館近年來遊客銳減,而在今年1月宣布倒閉,但水族館內的大量動物未獲得妥善安置。除了海豚「甜心」,另外還有46隻企鵝及數百隻魚類就這樣被留在水族館內,雖然仍有工作人員定時餵食,但媒體從館外拍攝會面可見,「甜心」孤獨地在水池內探頭往外看,企鵝則在殘破的設施中走動,宛如世界末日後只剩下動物獨留的狀態。

日本網友看見「甜心」和其他動物遭遺棄的畫面後,紛紛氣憤在網路上留言痛批館方,要求政府單位介入處理。目前已有一間度假飯店表示,願意收留這些可憐的海洋動物。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

聚甘新

非洲有機會「大停電」 專家:蓋水壩的趨勢可能錯了

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

聚甘新