<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Linux線程同步必知,常用方法揭秘!

      一、為什么要線程同步

      在Linux 多線程編程中,線程同步是一個非常重要的問題。如果線程之間沒有正確地同步,就會導致程序出現一些意外的問題,例如:

      1. 競態條件(Race Condition):多個線程同時修改同一個共享變量,可能會導致不可預測的結果,因為線程的執行順序是不確定的。
      2. 死鎖(Deadlock):當兩個或多個線程互相等待對方釋放資源時,可能會導致死鎖,這會導致程序無法繼續執行。
      3. 活鎖(Livelock):當多個線程相互響應對方的動作,而沒有任何進展時,可能會導致活鎖,這也會導致程序無法繼續執行。

      活鎖對話

      • 兩個人在走路時需要相互讓路,兩個人都想讓對方先通過,但最終還是沒有人通過,這就是一種活鎖情況

      讓路

      接下來將介紹互斥鎖、條件變量、信號量、讀寫鎖這幾種線程同步方法,并使用C語言代碼示例說明其使用方法。

      二、互斥鎖

      互斥鎖是一種用于線程同步的鎖,用于保護共享資源。只有擁有該鎖的線程才能訪問共享資源,其他線程需要等待鎖被釋放后才能繼續執行。

      在Linux環境下,我們可以使用pthread庫提供的互斥鎖函數來實現互斥鎖機制。以下是一些常用的互斥鎖函數:

      函數名 描述
      pthread_mutex_init 初始化互斥鎖
      pthread_mutex_lock 加鎖互斥鎖
      pthread_mutex_trylock 嘗試加鎖互斥鎖
      pthread_mutex_unlock 解鎖互斥鎖
      pthread_mutex_destroy 銷毀互斥鎖

      初始化互斥鎖

      在使用互斥鎖之前,需要先初始化互斥鎖。pthread_mutex_init函數用于初始化一個互斥鎖。函數原型如下:

      int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
      

      其中,mutex參數是一個指向pthread_mutex_t結構體的指針,用于指定要初始化的互斥鎖;attr參數是一個指向pthread_mutexattr_t結構體的指針,用于指定互斥鎖的屬性,通常設置為NULL。

      以下是一個初始化互斥鎖的例子:

      #include <pthread.h>
      
      pthread_mutex_t mutex;
      
      int main()
      {
          // 初始化互斥鎖
          pthread_mutex_init(&mutex, NULL);
          
          // ...
          
          // 銷毀互斥鎖
          pthread_mutex_destroy(&mutex);
          
          return 0;
      }
      
      

      加鎖互斥鎖

      加鎖互斥鎖用于保證同一時刻只有一個線程能夠訪問共享資源。pthread_mutex_lock函數用于加鎖一個互斥鎖。函數原型如下:

      int pthread_mutex_lock(pthread_mutex_t *mutex);
      

      其中,mutex參數是一個指向pthread_mutex_t結構體的指針,用于指定要加鎖的互斥鎖。

      以下是一個加鎖互斥鎖的例子:

      #include <pthread.h>
      
      pthread_mutex_t mutex;
      
      void* thread_func(void* arg)
      {
          // 加鎖互斥鎖
          pthread_mutex_lock(&mutex);
          
          // 訪問共享資源
          // ...
          
          // 解鎖互斥鎖
          pthread_mutex_unlock(&mutex);
          
          return NULL;
      }
      
      int main()
      {
          // 初始化互斥鎖
          pthread_mutex_init(&mutex, NULL);
          
          // 創建線程
          pthread_t tid;
          pthread_create(&tid, NULL, thread_func, NULL);
          
          // ...
          
          // 等待線程結束
          pthread_join(tid, NULL);
          
          // 銷毀互斥鎖
          pthread_mutex_destroy(&mutex);
          
          return 0;
      }
      
      

      嘗試加鎖互斥鎖

      嘗試加鎖互斥鎖與加鎖互斥鎖的主要區別在于,如果互斥鎖已經被其他線程鎖定了,嘗試加鎖互斥鎖將不會阻塞當前線程,而是會立即返回一個錯誤代碼。函數原型如下:

      int pthread_mutex_trylock(pthread_mutex_t *mutex);
      

      其中,mutex參數是一個指向pthread_mutex_t結構體的指針,用于指定要嘗試加鎖的互斥鎖。

      以下是一個嘗試加鎖互斥鎖的例子:

      #include <pthread.h>
      
      pthread_mutex_t mutex;
      
      void* thread_func(void* arg)
      {
          // 嘗試加鎖互斥鎖
          int ret = pthread_mutex_trylock(&mutex);
          if (ret == 0) {
              // 訪問共享資源
              // ...
              
              // 解鎖互斥鎖
              pthread_mutex_unlock(&mutex);
          } else {
              // 互斥鎖已經被其他線程鎖定了
              // ...
          }
          
          return NULL;
      }
      
      int main()
      {
          // 初始化互斥鎖
          pthread_mutex_init(&mutex, NULL);
          
          // 創建線程
          pthread_t tid;
          pthread_create(&tid, NULL, thread_func, NULL);
          
          // ...
          
          // 等待線程結束
          pthread_join(tid, NULL);
          
          // 銷毀互斥鎖
          pthread_mutex_destroy(&mutex);
          
          return 0;
      }
      
      

      解鎖互斥鎖

      解鎖互斥鎖用于釋放已經鎖定的互斥鎖。pthread_mutex_unlock函數用于解鎖一個互斥鎖。函數原型如下:

      int pthread_mutex_unlock(pthread_mutex_t *mutex);
      

      其中,mutex參數是一個指向pthread_mutex_t結構體的指針,用于指定要解鎖的互斥鎖。

      以下是一個解鎖互斥鎖的例子:

      #include <pthread.h>
      
      pthread_mutex_t mutex;
      
      void* thread_func(void* arg)
      {
          // 加鎖互斥鎖
          pthread_mutex_lock(&mutex);
          
          // 訪問共享資源
          //
      	// 解鎖互斥鎖
      	pthread_mutex_unlock(&mutex);
      
      	return NULL;
      }
      

      銷毀互斥鎖

      在不再需要使用互斥鎖時,需要將互斥鎖銷毀。pthread_mutex_destroy函數用于銷毀一個互斥鎖。函數原型如下:

      int pthread_mutex_destroy(pthread_mutex_t *mutex);
      

      其中,mutex參數是一個指向pthread_mutex_t結構體的指針,用于指定要銷毀的互斥鎖。

      以下是一個銷毀互斥鎖的例子:

      #include <pthread.h>
      
      pthread_mutex_t mutex;
      
      int main()
      {
          // 初始化互斥鎖
          pthread_mutex_init(&mutex, NULL);
          
          // ...
          
          // 銷毀互斥鎖
          pthread_mutex_destroy(&mutex);
          
          return 0;
      }
      
      

      示例程序

      下面是一個簡單的示例程序,演示了如何使用互斥鎖來同步兩個線程的訪問。

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      pthread_mutex_t mutex;
      int shared_data = 0;
      
      void *thread_func(void *arg)
      {
          int i;
          for (i = 0; i < 1000000; i++) {
              pthread_mutex_lock(&mutex);
              shared_data++;
              pthread_mutex_unlock(&mutex);
          }
          return NULL;
      }
      
      int main()
      {
          pthread_t thread1, thread2;
          pthread_mutex_init(&mutex, NULL);
          pthread_create(&thread1, NULL, thread_func, NULL);
          pthread_create(&thread2, NULL, thread_func, NULL);
          pthread_join(thread1, NULL);
          pthread_join(thread2, NULL);
          pthread_mutex_destroy(&mutex);
          printf("Shared data: %d\n", shared_data);
          return 0;
      }
      

      在這個程序中,thread_func函數是兩個線程執行的函數,它會對shared_data變量進行1000000次加一操作。

      為了確保多個線程不會同時訪問shared_data變量,我們使用了一個互斥鎖。當一個線程要訪問shared_data變量時,它會調用pthread_mutex_lock函數來加鎖。如果鎖已經被其他線程持有,那么這個線程就會被阻塞,直到鎖被釋放為止。當線程完成對shared_data變量的操作后,它會調用pthread_mutex_unlock函數來釋放鎖。

      在這個程序執行完畢后,我們可以通過打印shared_data變量的值來檢查程序是否正確地同步了兩個線程的訪問。如果程序正確地同步了線程的訪問,那么shared_data變量的值應該是2000000。

      ?? 在使用互斥鎖時,需要確保每個線程都在必要的時候釋放鎖。如果一個線程忘記釋放鎖,那么其他線程就會被永久地阻塞,程序就會死鎖。另外,過度使用互斥鎖也會降低程序的性能。

      ??因為加鎖和釋放鎖的過程需要消耗一定的時間和系統資源,所以在設計程序時需要盡可能減少加鎖和釋放鎖的次數。


      三、條件變量

      條件變量是Linux線程的另一種同步機制。它用于自動阻塞線程,直到某個特定事件發生或某個條件滿足為止,通常情況下,條件變量是和互斥鎖一起搭配使用的。使用條件變量主要包括兩個動作:

      • 一個線程等待某個條件滿足而被阻塞;

      • 另一個線程中,條件滿足時發出“信號”

      初始化條件變量

      在使用條件變量之前,需要先對其進行初始化。以下是一個初始化條件變量的示例:

      #include <pthread.h>
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      

      等待條件變量

      線程可以通過等待條件變量來暫停執行,并在條件變量被喚醒后繼續執行。以下是一個等待條件變量的示例:

      #include <pthread.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      
      void *thread_func(void *arg)
      {
          // 等待條件變量
          pthread_mutex_lock(&mutex);
          pthread_cond_wait(&cond, &mutex);
          pthread_mutex_unlock(&mutex);
      
          return NULL;
      }
      
      

      在上面的示例中,線程會在pthread_cond_wait函數處等待條件變量cond。

      在等待之前,線程必須先獲取互斥鎖mutex。等待函數會自動釋放互斥鎖,并在條件變量被喚醒后重新獲取互斥鎖。

      喚醒等待條件變量的線程

      線程可以通過發送信號來喚醒等待條件變量的線程。以下是一個發送信號的示例:

      #include <pthread.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      
      void *thread_func(void *arg)
      {
          // 等待條件變量
          pthread_mutex_lock(&mutex);
          pthread_cond_wait(&cond, &mutex);
          pthread_mutex_unlock(&mutex);
      
          return NULL;
      }
      
      int main()
      {
          // 喚醒等待條件變量的線程
          pthread_mutex_lock(&mutex);
          pthread_cond_signal(&cond);
          pthread_mutex_unlock(&mutex);
      
          return 0;
      }
      
      

      在上面的示例中,主線程通過發送信號來喚醒等待條件變量的線程。在發送信號之前,主線程必須先獲取互斥鎖mutex。

      廣播喚醒等待條件變量的線程

      有時候需要喚醒多個等待條件變量的線程,此時可以使用廣播機制。以下是一個廣播喚醒等待條件變量的線程的示例:

      #include <pthread.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      
      void *thread_func(void *arg)
      {
          // 等待條件變量
          pthread_mutex_lock(&mutex);
          pthread_cond_wait(&cond, &mutex);
          pthread_mutex_unlock(&mutex);
      
          return NULL;
      }
      
      int main()
      {
          // 廣播喚醒等待條件變量的線程
          pthread_mutex_lock(&mutex);
          pthread_cond_broadcast(&cond);
          pthread_mutex_unlock(&mutex);
      
          return 0; 
      }
      

      在上面的示例中,主線程通過廣播機制來喚醒等待條件變量的線程。在廣播之前,主線程必須先獲取互斥鎖mutex。

      等待特定條件的條件變量

      有時候需要等待特定條件的條件變量,此時可以在等待函數中加入判斷條件。以下是一個等待特定條件的條件變量的示例:

      #include <pthread.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      
      int condition = 0;
      
      void *thread_func(void *arg)
      {
          // 等待特定條件的條件變量
          pthread_mutex_lock(&mutex);
          while (condition == 0) {
              pthread_cond_wait(&cond, &mutex);
          }
          pthread_mutex_unlock(&mutex);
      
          return NULL;
      }
      
      int main()
      {
          // 設置特定條件并喚醒等待條件變量的線程
          pthread_mutex_lock(&mutex);
          condition = 1;
          pthread_cond_signal(&cond);
          pthread_mutex_unlock(&mutex);
      
          return 0;
      }
      
      

      在上面的示例中,線程會在while循環中等待特定條件的條件變量cond。在等待之前,線程必須先獲取互斥鎖mutex。

      主線程通過設置特定條件并發送信號來喚醒等待條件變量的線程。

      銷毀條件變量

      在不需要使用條件變量時,需要將其銷毀以釋放資源。以下是一個銷毀條件變量的示例:

      #include <pthread.h>
      
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      
      int main()
      {
          // 銷毀條件變量
          pthread_cond_destroy(&cond);
      
          return 0;
      }
      
      

      在上面的示例中,通過調用pthread_cond_destroy函數來銷毀條件變量cond。

      示例程序

      下面是一個簡單的示例程序,演示了如何使用條件變量來實現線程間的同步。

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      int shared_data = 0;
      
      void *thread_func1(void *arg)
      {
          printf("Thread 1 started\n");
          pthread_mutex_lock(&mutex);
          while (shared_data < 10) {
              pthread_cond_wait(&cond, &mutex);
          }
          printf("Thread 1 read shared_data: %d\n", shared_data);
          pthread_mutex_unlock(&mutex);
          printf("Thread 1 finished\n");
          return NULL;
      }
      
      void *thread_func2(void *arg)
      {
          printf("Thread 2 started\n");
          for (int i = 0; i < 10; i++) {
              pthread_mutex_lock(&mutex);
              shared_data++;
              printf("Thread 2 wrote shared_data: %d\n", shared_data);
              if (shared_data == 10) {
                  pthread_cond_signal(&cond);
              }
              pthread_mutex_unlock(&mutex);
          }
          printf("Thread 2 finished\n");
          return NULL;
      }
      
      int main()
      {
          pthread_t thread1, thread2;
          pthread_create(&thread1, NULL, thread_func1, NULL);
          pthread_create(&thread2, NULL, thread_func2, NULL);
          pthread_join(thread1, NULL);
          pthread_join(thread2, NULL);
          pthread_mutex_destroy(&mutex);
          pthread_cond_destroy(&cond);
          return 0;
      }
      
      

      在這個程序中,我們創建了兩個線程,分別執行thread_func1thread_func2函數。

      thread_func1函數等待shared_data變量的值達到10后再繼續執行,并輸出到控制臺上。

      thread_func2函數將shared_data變量的值加1,并在shared_data變量的值等于10時,發送一個信號通知thread_func1函數可以繼續執行。

      需要注意的是,我們在thread_func1函數中使用了pthread_cond_wait函數來等待條件變量,而在thread_func2函數中使用了pthread_cond_signal函數來發送條件變量。

      當一個線程等待條件變量時,它會釋放掉與條件變量相關的鎖,并進入睡眠狀態。當另一個線程發送條件變量時,它會喚醒等待條件變量的線程,并重新獲取與條件變量相關的鎖。

      四、信號量

      信號量是一種計數器,用于同步和互斥訪問共享資源。它是一個整數變量,可以使用原子操作來訪問。

      當多個線程需要同時訪問共享資源時,它們必須先獲取一個信號量,然后訪問資源,并在訪問完成后釋放信號量。

      如果信號量的計數器值為零,則線程會被阻塞,直到有其他線程釋放信號量。

      在Linux中,信號量的API是sem_initsem_waitsem_postsem_destroy

      初始化信號量

      int sem_init(sem_t *sem, int pshared, unsigned int value);
      

      sem_init() 函數用于初始化信號量。它接受三個參數:

      • sem:指向信號量的指針
      • pshared:指示信號量是進程共享還是線程共享的標志。如果為 0,則信號量被限制在當前進程的線程中;否則,信號量可以被多個進程共享。
      • value:信號量的初始值。如果為 0,則調用線程將等待,直到其他線程釋放信號量。

      等待信號量

      int sem_wait(sem_t *sem);
      

      sem_wait() 函數用于等待信號量。

      如果信號量的值大于 0,則將該值減 1 并返回。否則,調用線程將被阻塞,直到其他線程釋放信號量為止。

      釋放信號量

      int sem_post(sem_t *sem);
      

      sem_post() 函數用于釋放信號量。它將信號量的值加 1,并通知等待該信號量的線程或進程。

      銷毀信號量

      int sem_destroy(sem_t *sem);
      

      sem_destroy() 函數用于銷毀信號量。它將釋放信號量使用的資源,并將其重置為未初始化狀態。但是,只有在沒有線程等待信號量時才能銷毀它。

      示例程序

      下面是一個簡單的示例程序,演示了如何使用信號量來實現生產者消費者模式。

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      #include <semaphore.h>
      
      #define BUFFER_SIZE 10
      
      sem_t empty, full;
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      int buffer[BUFFER_SIZE];
      int buffer_index = 0;
      
      void *producer(void *arg)
      {
          printf("Producer started\n");
          for (int i = 0; i < BUFFER_SIZE * 2; i++) {
              sem_wait(&empty);
              pthread_mutex_lock(&mutex);
              buffer[buffer_index] = i;
              buffer_index++;
              printf("Produced: %d\n", i);
              pthread_mutex_unlock(&mutex);
              sem_post(&full);
          }
          printf("Producer finished\n");
          return NULL;
      }
      
      void *consumer(void *arg)
      {
          printf("Consumer started\n");
          for (int i = 0; i < BUFFER_SIZE * 2; i++) {
              sem_wait(&full);
              pthread_mutex_lock(&mutex);
              buffer_index--;
              printf("Consumed: %d\n", buffer[buffer_index]);
              pthread_mutex_unlock(&mutex);
              sem_post(&empty);
          }
          printf("Consumer finished\n");
          return NULL;
      }
      
      int main()
      {
          sem_init(&empty, 0, BUFFER_SIZE);
          sem_init(&full, 0, 0);
          pthread_t producer_thread, consumer_thread;
          pthread_create(&producer_thread, NULL, producer, NULL);
          pthread_create(&consumer_thread, NULL, consumer, NULL);
          pthread_join(producer_thread, NULL);
          pthread_join(consumer_thread, NULL);
          sem_destroy(&empty);
          sem_destroy(&full);
          pthread_mutex_destroy(&mutex);
          return 0;
      }
      

      在這個程序中,我們使用了兩個信號量,一個是empty,用于表示緩沖區中的空閑空間數量,另一個是full,用于表示緩沖區中已經存儲的數據數量。

      在生產者線程中,當需要向緩沖區中添加數據時,它會先等待empty信號量,以確保緩沖區中有足夠的空間來存儲數據。

      一旦empty信號量的計數器值大于零,生產者線程會使用pthread_mutex_lock來保護緩沖區,然后向緩沖區中添加數據,并發送一個full信號量的信號,以通知消費者線程可以從緩沖區中獲取。

      五、讀寫鎖

      Linux讀寫鎖(Read-Write Lock)是一種用于多線程并發控制的同步機制,它允許多個線程同時讀取共享資源,但在寫入操作時,只允許一個線程進行,以避免數據競爭和不一致性。

      初始化讀寫鎖

      int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); 
      

      其中rwlock為讀寫鎖指針,attr為讀寫鎖屬性指針。如果attr為NULL,則使用默認屬性。成功返回0,失敗返回錯誤碼。

      銷毀讀寫鎖

      int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 
      

      其中rwlock為讀寫鎖指針。成功返回0,失敗返回錯誤碼。

      加讀鎖

      int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 
      

      其中rwlock為讀寫鎖指針。如果當前有寫鎖或正在等待寫鎖,則阻塞等待。成功返回0,失敗返回錯誤碼。

      加寫鎖

      int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 
      

      其中rwlock為讀寫鎖指針。如果當前有讀鎖或寫鎖或正在等待讀鎖或寫鎖,則阻塞等待。成功返回0,失敗返回錯誤碼。

      解鎖

      int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
      

      其中rwlock為讀寫鎖指針。成功返回0,失敗返回錯誤碼。

      示例程序

      下面是一個簡單的使用讀寫鎖的例子,用于演示讀寫鎖的使用方法。

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      pthread_rwlock_t rwlock;
      int count = 0;
      
      void *write_thread(void *arg)
      {
          while(1) {
              pthread_rwlock_wrlock(&rwlock);
              count++;
              printf("write thread: count=%d\n", count);
              pthread_rwlock_unlock(&rwlock);
              sleep(1);
          }
          return NULL;
      }
      
      void *read_thread(void *arg)
      {
          while(1) {
              pthread_rwlock_rdlock(&rwlock);
              printf("read thread: count=%d\n", count);
              pthread_rwlock_unlock(&rwlock);
              sleep(1);
          }
          return NULL;
      }
      
      int main()
      {
          pthread_t tid1, tid2;
          pthread_rwlock_init(&rwlock, NULL);
      
          pthread_create(&tid1, NULL, write_thread, NULL);
          pthread_create(&tid2, NULL, read_thread, NULL);
      
          pthread_join(tid1, NULL);
          pthread_join(tid2, NULL);
      
          pthread_rwlock_destroy(&rwlock);
      
          return 0;
      }
      
      

      該例子中,我們定義了兩個線程write_thread和read_thread。

      其中write_thread對共享變量count進行寫操作,read_thread對共享變量count進行讀操作。

      我們使用pthread_rwlock_init函數初始化讀寫鎖,然后使用pthread_rwlock_wrlock函數和pthread_rwlock_rdlock函數對共享變量進行加鎖,保證寫線程和讀線程互斥訪問共享變量。

      在加鎖后,線程對共享變量進行操作,然后使用pthread_rwlock_unlock函數進行解鎖。最后,我們使用pthread_rwlock_destroy函數銷毀讀寫鎖。

      當我們運行這個程序時,會發現write_thread線程每隔一秒鐘就會增加共享變量count的值,并打印出來。

      而read_thread線程每隔一秒鐘就會讀取并打印共享變量count的值。

      由于讀寫鎖的存在,這兩個線程可以安全地并發訪問共享變量,避免了數據競爭和不一致性的問題。

      小結

      了解這些同步機制可以幫助我們寫出高效且正確的多線程應用程序。不同的同步機制適用于不同的情況,選擇適當的同步機制也是非常重要的。

      posted @ 2023-04-01 08:20  知微之見  閱讀(655)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩在线视频一区二区三区| 精品午夜福利在线视在亚洲| 浪潮av色综合久久天堂| 99欧美日本一区二区留学生| 性色av无码久久一区二区三区 | 欧美成人午夜在线观看视频| 性欧美三级在线观看| 成在人线AV无码免观看| 国产良妇出轨视频在线观看| 欧美粗大| 乱老年女人伦免费视频| 亚洲18禁一区二区三区| 国产成年码av片在线观看| 麻豆一区二区三区蜜桃免费| 亚洲成人www| 国内精品一区二区不卡| 97人妻精品一区二区三区| 无码视频伊人| 美女自卫慰黄网站| 无码少妇一区二区| 美女自卫慰黄网站| 人妻互换一二三区激情视频| 白嫩人妻精品一二三四区| 黑人大荫道bbwbbb高潮潮喷| 91久久国产成人免费观看| 亚洲精品一二三四区| 亚洲av肉欲一区二区| 久久精品国产只有精品96| 国产亚洲精品AA片在线爽| 一本色道久久—综合亚洲| 丰满少妇呻吟高潮经历| 野外做受三级视频| 国产一区二区三区精品片| 国产精品一区二区久久岳| 最新中文字幕国产精品| 久久综合精品成人一本| 亚洲AV无码久久精品成人| 国产精品美女久久久久久麻豆| 精品国产一区二区色老头| 影音先锋人妻啪啪av资源网站| 99在线精品国自产拍中文字幕|