【问题标题】:printing odd and even number printing alternately using threads in C++在 C++ 中使用线程交替打印奇数和偶数打印
【发布时间】:2013-02-01 06:48:36
【问题描述】:

Odd even number printing using thread 我遇到了这个问题,想讨论 C++ 中的解决方案。我能想到的使用 2 个二进制信号量奇数和偶数信号量。偶数信号量初始化为 1,奇数信号量初始化为 0。

**T1 thread function** 
funOdd()
{  
  wait(even)  
  print odd;  
  signal(odd)  
}


**T2 thread function**
funEven()  
{  
  wait(odd)  
  print even  
  signal(even)  
}  

除此之外,如果我的函数只生成数字并且有第三个线程 T3 将打印这些数字,那么理想的设计应该是什么?我使用了一个数组,其中奇数将放置在奇数位置,偶数将放置在偶数位置。 T3 将从这个数组中读取,这将避免任何线程在这个数组上的安全,如果 T3 没有找到任何索引,那么它将等到该索引被填充。另一种解决方案是使用一个队列,该队列将具有一个互斥体,T1 和 T2 在插入时可以使用该互斥体。

请对此解决方案发表评论,以及如何提高效率。

编辑使问题更加清晰:总体问题是我有两个生产者(T1,T2)和一个消费者(T3),我的生产者是相互依赖的。

【问题讨论】:

  • 如果你想要串行行为,不要使用线程。
  • 在这种情况下我可以避免线程,但这是非常有效的场景,我的 2 个线程相互依赖。
  • 我非常努力地关注这个问题,并发现如果没有 code(一种近乎通用的语言,除了不寻常的 var 名称),描述就很混乱跟随,在某些地方几乎是不可能的。 看起来您有两个生产者 (T1,T2) 和一个消费者 (T3),但您的生产者是相互依赖的。我也很好奇 “如果 T3 没有找到任何索引,那么它将等到该索引被填充。” 在没有 some 类型的同步的情况下会保持不变。最后,“非常有效”?有效有点。是,或者不是。
  • @WhozCraig T3 可以休眠一段时间并再次检查该索引。如果索引已填充,则移动到下一个 else 再次睡眠。为什么你认为我们需要对数组进行同步你能解释一下我需要同步的场景吗?
  • 这个问题有后续吗?最后,你自己的答案是什么?

标签: c++ multithreading thread-safety semaphore


【解决方案1】:

使用条件变量

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mu;
std::condition_variable cond;
int count = 1;

void PrintOdd()
{
    for(; count < 100;)
    {
        std::unique_lock<std::mutex> locker(mu);
        cond.wait(locker,[](){ return (count%2 == 1); });
        std::cout << "From Odd:    " << count << std::endl;
        count++;
        locker.unlock();
        cond.notify_all();
    }

}

void PrintEven()
{
    for(; count < 100;)
    {
        std::unique_lock<std::mutex> locker(mu);
        cond.wait(locker,[](){ return (count%2 == 0); });
        std::cout << "From Even: " << count << std::endl;
        count++;
        locker.unlock();
        cond.notify_all();
    }
}

int main()
{
    std::thread t1(PrintOdd);
    std::thread t2(PrintEven);
    t1.join();
    t2.join();
    return 0;
}

【讨论】:

  • 如果t2线程先执行会不会导致死锁? PrintEven() 获取锁然后等待计数变为偶数。但是count是1,只有在PrintOdd()执行count++时才会变为偶数。 PrintOdd() 正在等待锁,所以无法执行。
  • @MaskedMan:不,不会的。这就是条件变量正在做的事情。如果条件不满足,它会释放锁并进入睡眠模式。所以如果 t2 先获得锁,那么它将进入等待状态,因为 coun%2 == 0 条件将失败。当 t2 释放锁时, t1 线程可以获取锁并执行。一旦执行完成,它会调用 notify_all(),它会通知 t2 线程说现在你可以检查条件是否满足,如果条件满足,它重新获取锁并打印偶数和序列继续。
  • 程序中有一个细微的错误。即使我们希望程序打印低于 100 的值(参见条件 count &lt; 100),偶数线程也可能会打印 100 作为最后结果。
  • 做 locker.unlock(); unique_lock 需要?不是自动解锁吗?
【解决方案2】:

使用条件变量的解决方案。

#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex oddevenMu;
condition_variable condVar;
int number = 1;

void printEvenOdd(bool isEven, int maxnubmer)
{
    unique_lock<mutex> ul(oddevenMu);
    while (number < maxnubmer)
    {
        condVar.wait(ul, [&]() {return number % 2 == isEven;});
        cout << number++ << " ";
        condVar.notify_all();
    }

}

int main(string args[])
{
    thread oddThread(printEvenOdd, false, 100);
    thread evenThread(printEvenOdd, true, 100);
    oddThread.join();
    evenThread.join();
    return 0;
}

【讨论】:

    【解决方案3】:
     #include  <stdio.h>
     #include  <stdlib.h>
     #include  <iostream>
     #include  <pthread.h>
     #include  <semaphore.h>
    
      sem_t sem;
      sem_t sem2;
      using namespace std ;
    
    int count = 1;
    
    void increment(int x)
    {
        cout << "called by thread : " << x << "count is : " << count ++ << "\n";
    }
    
    void *printAltmessage1(void *thread_value)
    {
        for(int m=0; m < (*(int *)thread_value); m++)
        {
            if (sem_wait(&sem) == 0)
            {
                cout << " Thread printAltmessage1 is executed" <<"\n";  
                increment(1);
                sem_post(&sem2);
            }
        }
    }
    
    void *printAltmessage2(void *thread_value)
    {
        for(int m=0; m < (*(int *)thread_value); m++)
        {
            if (sem_wait(&sem2) == 0)
            {
                cout << " Thread printAltmessage2 is executed" <<"\n";
                increment(2);  
                sem_post(&sem);
            }
        }
    }
    
    int main()
    {
         sem_init(&sem,0, 1);
         sem_init(&sem2,0, 0);
         pthread_t threads[2];
         int x =8;
         for(int i=0;i<2;i++)
         {
              if(i==0)
              int rc =pthread_create(&threads[i],NULL,printAltmessage1,(void*)&x);
              else
              int rc =pthread_create(&threads[i],NULL,printAltmessage2,(void*)&x);
          }
          pthread_exit(NULL);
          return 0;
    }
    

    【讨论】:

      【解决方案4】:

      这是您可以参考的最简单的解决方案:

      #include<iostream>
      #include<mutex>
      #include<pthread.h>
      #include<cstdlib>
      int count=0;
      using namespace std;
      mutex m;
      void* printEven(void *a)
      {
         while(1)
         {
             m.lock();
             if(count%2==0)
             {
                cout<<" I am Even"<<count<<endl;
                count++;
             }
             if(count==100)
                 break;
             m.unlock();
         }
      }
      void* printOdd(void *b)
      {
          while(1)
          {
             m.lock();
             if(count%2!=0)
             {
                 cout<<"I am odd"<<count<<endl;
                 count++;
             }
             if(count>100)
                break;
             m.unlock();
          }
       }
       int main()
       {
           int *ptr = new int();
           pthread_t thread1, thread2;
           pthread_attr_t attr;
           pthread_attr_init(&attr);
           pthread_create(&thread1,&attr,&printEven,NULL);
           pthread_create(&thread2,&attr,&printOdd, NULL);
           pthread_join(thread1,&ptr);
           pthread_join(thread2,&ptr);
           delete ptr;
       }
      

      【讨论】:

      • ptr 的分配解除分配不匹配。 free(ptr) 应改为 delete ptr
      【解决方案5】:

      这是使用单一功能的简单解决方案。

      #include <iostream>
      #include <thread>
      #include <condition_variable>
      using namespace std;
      
      mutex mu;
      condition_variable cond;
      int count = 1;
      
      void PrintOddAndEven(bool even, int n){
          while(count < n){
              unique_lock<mutex> lk(mu);
              cond.wait(lk, [&](){return count%2 == even;});
              cout << count++ << " ";
              lk.unlock();
              cond.notify_all();
          }
      }
      
      int main() {
          int n = 10;
          thread t1(PrintOddAndEven, true, n);
          thread t2(PrintOddAndEven, false, n);
      
          t1.join();
          t2.join();
          return 0;
      }
      

      【讨论】:

        【解决方案6】:
            #include <iostream>
            #include <thread>
            #include <mutex> 
            using namespace std;
        
            std::mutex m;
            int count = 0;
        
            void printEven()
            {
                cout << "Entered Even\n" << endl;
                while(count <= 10)
                {
                    m.lock();
                    if(count%2 == 0)
                        cout << count++ << " ";
                     m.unlock();
                }
            }
            
            void printOdd()
            {
                cout << "Entered Odd" << endl;
                while(count < 10)
                {
                     m.lock();
                    if(count%2 == 1)
                        cout << count++ << " ";
                     m.unlock();
                }
            }
        
            int main()
            {
               std::thread t1(printOdd);
               std::thread t2(printEven);
               t1.join();
               t2.join();
                return 0;
            }
        

        【讨论】:

        • 最简单的只有互斥体和不使用条件变量:)
        • 如果连线程都称为 1st,你如何设法打印 1?你将如何保持正确的顺序?
        【解决方案7】:

        我不明白您为什么要使用三个单独的线程来进行串行行为。但无论如何我都会回答:)

        一种解决方案是使用修改后的生产者/消费者模式,在生产者和消费者之间使用prioritized queue。队列上的排序操作将取决于发布消息的整数值。消费者将查看队列中的一个元素并检查它是否是下一个预期元素。如果没有,它会休眠/等待。

        一点代码:

        class Elt implements Comparable<Elt> {
          int value;
          Elt(value) { this.value=value; }
          int compare(Elt elt);
        }
        
        class EltQueue extends PriorityBlockingQueue<Elt> { // you shouldn't inherit colelctions, has-a is better, but to make it short
          static EltQueue getInstance(); // singleton pattern
        }
        
        class Consumer{
          Elt prevElt = new Elt(-1);
          void work()
          {
            Elt elt = EltQueue.getInstance().peek();
            if (elt.getValue() == prevElt.getValue()+1)) {
              EltQueue.getInstance().poll();
              //do work on Elt
            }
          }
        }
        
        class Producer {
          int n=0; // or 1!
          void work() {
            EltQueue.getInstance().put(new Elt(n+=2));
          }
        }
        

        【讨论】:

        • @J99 或多或少是 Java。语言无关紧要,背后不变
        【解决方案8】:

        首先,这两个函数至少应该包含一个循环,(除非你只想要一个数字)

        一个更标准的解决方案(重新映射您的想法)是拥有一个包含互斥锁和两个条件变量(奇数和偶数)加上一个返回值和另一个打印条件的全局结构。而不是使用 uique_lock 来处理同步。

        在伪代码中:

        struct global_t
        {
            mutex mtx;
            int value = {0};
            condition_variable be_odd, be_even, print_it;
            bool bye = {false};
        
            global_t() { be_odd.notify(); }
        } global;
        
        void odd_generator()
        {
            int my_odd = 1;
            for(;;)
            {
                unique_lock lock(global.mtx);
                if(global.bye) return;
                global.be_odd.wait(lock);
                global_value = my_odd; my_odd+=2;
                global.print_it.notify();
                if(my_odd > 100) bye=true;
            } //let RAII to manage wait states and unlocking
        };
        
        void even_generator()
        { /* same as odd, with inverted roles */ }
        
        void printer()
        {
            for(;;)
            {
                unique_lock lock(global.mtx);
                if(bye) return;
                global.ptint_it.wait(lock);
                std::cout << global.value << std::endl;
                ((global.value & 1)? global.be_even: global.be_odd).notify();
            }
        }
        
        
        int main()
        {
            thread oddt(odd_generator), event(even_generator), printt(printer);
            oddt.join(), event.join(), printer.join();
        }
        

        请注意,除了教学目的之外,此解决方案不会为打印计数器值的简单循环增加任何价值,因为永远不会有真正的并发。

        还请注意(为了避免全局变量),您可以将所有内容包装到一个类中(使实际的 main 成为类方法)并在新 main 内的堆栈上实例化该类。

        【讨论】:

          【解决方案9】:

          解决方案基于 C++11 关键代码部分,即 mutex

          这是工作代码,后面是解释。

          在 VS2013 上测试和工作:

          using namespace std;
          #include <iostream>
          #include <string>
          #include <thread>
          #include <mutex>
          
          std::mutex mtx;
          
          void oddAndEven(int n, int end);
          
          int main()
          {
          std::thread odd(oddAndEven, 1, 10);
          std::thread Even(oddAndEven, 2, 10);
          
          odd.join();
          Even.join();
          
          return 0;
          }
          
          
          
          void oddAndEven(int n, int end){
          int x = n;
          for (; x < end;){
              mtx.lock();
              std::cout << n << " - " << x << endl;
              x += 2;
              mtx.unlock();
              std::this_thread::yield();
              continue;
           }
          }
          

          即:

          线程odd 转到oddAndEven 方法,起始编号为1,因此他是奇数。他是第一个获得mtx.lock()锁的人。

          与此同时,线程 Even 也尝试获取锁,但线程 odd 先获得了它,因此线程 Even 等待。

          回到线程odd(它有锁),他打印数字1并用mtx.unlock()释放锁。此时,我们希望线程 Even 获得锁并打印 2,因此我们通过写 std::this_thread::yield() 通知线程 Even。然后线程 Even 做同样的事情。

          等等等等等等

          【讨论】:

          • 如果其中一个线程比另一个线程花费更多时间怎么办?我的意思是,如果您在锁 sleep_for(rnd_number) 内添加,则它的打印顺序可能会颠倒。我想必须使用 condition_variable
          • 刚刚遇到这个。如果yield没有做任何事情,我的意思是再次安排相同的线程。然后顺序会改变。可能会得到0 2 4 1 3...
          • 嘿@GauravSehgal,很抱歉,我不明白你的意思。如果您认为有错误,您可以编辑答案..
          【解决方案10】:
          #include <iostream>
          #include <thread>
          #include <mutex>
          
          std::mutex mu;
          unsigned int change = 0;
          
          void printConsecutiveNumbers(int start, int end,unsigned int consecutive)
          {
              int x = start;
              while (x < end)
              {
                  //each thread has check there time is coming or not
                  if (change % consecutive == start)
                  {
                      std::unique_lock<std::mutex> locker(mu);
                      std::cout << "Thread " << start << " -> " << x << std::endl;
                      x += consecutive;
                      change++;
                      //to counter overflow
                      change %= consecutive;
                  }
              }
          }
          
          int main()
          {
              //change num = 2 for printing odd and even
              const int num = 7;
              const int endValue = 1000;
              std::thread threads[num];
              //Create each consecutive threads
              for (int i = 0; i < num; i++)
              {
                  threads[i] = std::thread(printConsecutiveNumbers, i, endValue, num);
              }
          
              //Joins all thread to the main thread
              for (int i = 0; i < num; i++)
              {
                  threads[i].join();
              }
          
              return 0;
          }
          

          【讨论】:

            【解决方案11】:

            此代码将起作用。我已经在 Visual Studio 2017 上对其进行了测试

            #include "stdafx.h"
            #include <iostream>
            #include <mutex>
            #include <thread>
            #include <condition_variable>
            using namespace std;
            mutex m;
            condition_variable cv;
            int num = 1;
            
            
            void oddThread() {​​​​​​​
                
                for (; num < 10;) {​​​​​​​
                    unique_lock<mutex> lg(m);
                    cv.wait(lg, [] {​​​​​​​return (num % 2 ==1); }​​​​​​​);
                    cout << "From odd Thread " << num << endl;
                    num++;
                    lg.unlock();
                    cv.notify_one();
                }​​​​​​​
            }​​​​​​​
            void evenThread() {​​​​​​​
                for (; num < 100;) {​​​​​​​
                    unique_lock<mutex> lg(m);
                    cv.wait(lg, [] {​​​​​​​return (num % 2 == 0); }​​​​​​​);
                    cout << "From even Thread " << num << endl;
                    num++;
                    lg.unlock();
                    cv.notify_one();
                }​​​​​​​
            }​​​​​​​
            
            
            int main() {​​​​​​​
                
                thread t1{​​​​​​​ oddThread}​​​​​​​; //odd function thread
                thread t2{​​​​​​​ evenThread}​​​​​​​;
                t1.join();
                t2.join();
                cin.get();
                return 0;
            }​​​​​​​
            

            输出

            来自奇数线程:1 来自偶数线程:2 来自奇数线程:3 来自偶数线程:4 来自奇数线程:5 来自偶数线程:6 来自奇数线程:7 来自偶数线程:8 来自奇数线程:9 来自偶数线程:10

            【讨论】:

              【解决方案12】:
              #include <iostream>
              #include <thread>
              #include <mutex>
              #include <condition_variable>
              using namespace std;
              std::mutex m;
              std::condition_variable cv;
              int counter =1;
              
              void printEven()
              {
                  std::unique_lock<std::mutex> lk(m);
                  while(1)
                  {
                      if(counter > 10)
                          break;
                      if(counter %2 != 0)
                      {
                          cv.wait (lk);
                      }
                      else
                      {
                          cout << "counter : " << counter << endl;
                          counter++;
                          //lk.unlock();
                          cv.notify_one();
                      }
                  
                  
                  }
              }
              
              
              void printOdd()
              {
                  std::unique_lock<std::mutex> lk(m);
                  
                  while(1)
                  {
                      if(counter > 9)
                      break;
                      if(counter %2 == 0)
                      {
                          cv.wait (lk);
                      }
                      else
                      {
                          cout << "counter : " << counter << endl;
                          counter++;
                          //lk.unlock();
                          cv.notify_one();
                      }
                  
                  
                  }
              }
              
              int main()
              {
                  std::thread t1(printEven);
                  std::thread t2(printOdd);
                  t1.join();
                  t2.join();
                  cout << "Main Ends" << endl;
              }
              

              【讨论】:

                【解决方案13】:

                我使用匿名 func (lambda) 来执行此操作,并将 cond 变量和互斥锁组合在一起。

                #include <iostream>
                #include <thread>
                #include <condition_variable>
                #include <mutex>
                #include <chrono>
                
                using namespace std; 
                
                int main() {
                    int count = 1;
                    mutex mtx;
                    condition_variable condition;
                    const int ITERATIONS = 20; // iterations
                
                    //prints odd numbers
                    thread t1([&]() {
                        while (count < ITERATIONS)
                        {
                            unique_lock <mutex> lock(mtx);
                            condition.wait(lock, [&]() {
                                return count % 2 != 0;
                                });
                
                            cout << "thread1 prints: " << count << endl;
                            count++;
                            lock.unlock();
                            condition.notify_all();
                        }
                    });
                    
                    thread t2([&]
                        {
                            while (count < ITERATIONS)
                            {
                                unique_lock <mutex> lock(mtx);
                                condition.wait(lock, [&]() {
                                    return count % 2 == 0;
                                    });
                                cout << "thread2 prints: " << count << endl;
                                count++;
                                lock.unlock();
                                condition.notify_all();
                            }
                        });
                
                    t1.join();
                    t2.join();
                 }
                

                【讨论】:

                  【解决方案14】:
                  #include "threadFunc.hpp"
                  #include <iostream>
                  #include <thread>
                  #include <mutex>
                  #include <condition_variable>
                  
                  using namespace std;
                  
                  mutex t1;
                  condition_variable cond;
                  
                  
                  int number = 11;
                  int count = 0;
                  
                  void printEven()
                  {
                      while(1)
                      {
                          unique_lock<mutex> ul(t1);
                          if(count< number)
                          {
                              if(count % 2 != 0)
                              {
                                  cond.wait(ul);
                              }
                  
                              cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
                              count++;
                          }
                          if(count > number)
                              break;
                  
                          ul.unlock();
                          cond.notify_all();
                      }
                  
                  }
                  
                  void printOdd()
                  {
                      while(1)
                      {
                          unique_lock<mutex> ul(t1);
                          if(count< number)
                          {
                              if(count % 2 == 0)
                              {
                                  cond.wait(ul);
                              }
                  
                              cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
                              count++;
                          }
                          if(count > number)
                              break;
                  
                          ul.unlock();
                          cond.notify_all();
                      }
                  
                  }
                  

                  【讨论】:

                    【解决方案15】:
                    #include <bits/stdc++.h>
                    #include <stdlib.h>
                    #include <unistd.h>
                    #include <thread>
                    #include <mutex>
                    #include <condition_variable>
                    using namespace std;
                    
                    mutex m;
                    condition_variable cv;
                    unique_lock<mutex> lck(m);
                    
                    void *printeven(void *arg)
                    {
                        int *n = (int *)arg;
                        while (*n <= 100)
                        {
                            cv.wait(lck);
                            *n = *((int *)arg);
                            cout << this_thread::get_id() << " : " << *n << endl;
                            *n = *n + 1;
                            cv.notify_one();
                        }
                        exit(0);
                    }
                    
                    void *printodd(void *arg)
                    {
                        int *n = (int *)arg;
                        while (*n <= 100)
                        {
                            *n = *((int *)arg);
                            cout << this_thread::get_id() << " : " << *n << endl;
                            *n = *n + 1;
                            cv.notify_one();
                            cv.wait(lck);
                        }
                        exit(0);
                    }
                    
                    int main()
                    {
                        int num = 1;
                        pthread_t p1 = 1;
                        pthread_t p2 = 2;
                    
                        pthread_create(&p1, NULL, printodd, &num);
                        pthread_create(&p2, NULL, printeven, &num);
                    
                        pthread_join(p1, NULL);
                        pthread_join(p2, NULL);
                        return 0;
                    }
                    

                    【讨论】:

                    【解决方案16】:
                    #include <iostream>
                    #include <thread>
                    #include <mutex>
                    #include <condition_variable>
                    
                    std::mutex mtx;
                    std::condition_variable even_to_odd;
                    std::condition_variable odd_to_even;
                    unsigned int count = 1;
                    constexpr int MAX_COUNT = 20;
                    
                    void even(int n) {
                        for (int i = n; i <= MAX_COUNT; i++) {
                            std::unique_lock<std::mutex> lock(mtx);
                            if (i %2 == 0) {
                                odd_to_even.wait(lock);
                                std::cout << "Even: " << i << std::endl;
                                even_to_odd.notify_one();
                            }
                        }
                    }
                    
                    void odd(int n) {
                        for (int i = n; i <= MAX_COUNT; i++) {
                            std::unique_lock<std::mutex> lock(mtx);
                            if (i == 1) {
                                std::cout << "Odd : " << i << std::endl;
                                odd_to_even.notify_one();
                            }
                            else if (i % 2 != 0) {
                                even_to_odd.wait(lock);
                                std::cout << "Odd : " << i << std::endl;
                                odd_to_even.notify_one();
                            }
                        }
                    }
                    
                    int main() {
                        std::thread thread1(even,count);
                        std::thread thread2(odd,count);
                    
                        thread1.join();
                        thread2.join();
                        return 0;
                    }
                    

                    【讨论】:

                      【解决方案17】:

                      请看下面的工作代码(VS2005)

                      #include <windows.h>
                      #include <stdlib.h>
                      
                      #include <iostream>
                      #include <process.h>
                      
                      #define MAX 100
                      int shared_value = 0;
                      
                      CRITICAL_SECTION cs;
                      
                      unsigned _stdcall even_thread_cs(void *p)
                      {
                      
                          for( int i = 0 ; i < MAX ; i++ )
                          {
                              EnterCriticalSection(&cs);
                      
                              if( shared_value % 2 == 0 )
                              {
                                  printf("\n%d", i);
                              }
                      
                      
                              LeaveCriticalSection(&cs);
                      
                          }
                          return 0;
                      }
                      
                      unsigned _stdcall odd_thread_cs(void *p)
                      {
                          for( int i = 0 ; i < MAX ; i++ )
                          {
                              EnterCriticalSection(&cs);
                      
                              if( shared_value % 2 != 0 )
                              {
                                  printf("\n%d", i);
                              }
                      
                              LeaveCriticalSection(&cs);  
                      
                          }
                      
                          return 0;
                      }
                      
                      
                      int main(int argc, char* argv[])
                      {
                           InitializeCriticalSection(&cs);
                      
                          _beginthreadex(NULL, NULL, even_thread_cs, 0,0, 0);
                          _beginthreadex(NULL, NULL, odd_thread_cs, 0,0, 0);
                      
                          getchar();
                          return 0;
                      }
                      

                      在这里,使用共享变量shared_value,我们正在同步even_thread_csodd_thread_cs。 请注意,不使用睡眠。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-08-26
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-05-17
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多