Linux多线程——使用互斥量同步线程
生活随笔
收集整理的這篇文章主要介紹了
Linux多线程——使用互斥量同步线程
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
前文再續(xù),書接上一回,在上一篇文章:Linux多線程——使用信號量同步線程中,我們留下了一個如何使用互斥量來進(jìn)行線程同步的問題,本文將會給出互斥量的詳細(xì)解說,并用一個互斥量解決上一篇文章中,要使用兩個信號量才能解決的只有子線程結(jié)束了對輸入的處理和統(tǒng)計后,主線程才能繼續(xù)執(zhí)行的問題。
一、什么是互斥量
互斥量是另一種用于多線程中的同步訪問方法,它允許程序鎖住某個對象,使得每次只能有一個線程訪問它。為了控制對關(guān)鍵代碼的訪問,必須在進(jìn)入這段代碼之前鎖住一個互斥量,然后在完成操作之后解鎖。
二、互斥量的函數(shù)的使用
它們的定義與使用信號量的函數(shù)非常相似,它們的定義如下: [cpp]?view plaincopyprint? #include?<pthread.h>?? int?pthread_mutex_init(pthread_mutex_t?*mutex,?const?pthread_mutexattr_t?*mutexattr);?? ?? int?pthread_mutex_lock(pthread_mutex_t?*mutex);?? ?? int?pthread_mutex_unlock(pthread_mutex_t?*mutex);?? ?? int?pthread_mutex_destroy(pthread_mutex_t?*mutex);??
它們的意義就如它們的名字所示的那樣,成功時返回0,失敗時返回錯誤代碼,它們并不設(shè)置errno。
pthread_mutex_init函數(shù)中的參數(shù)mutexattr指定互斥量的屬性,在這里我們并不關(guān)心互斥量的屬性,所以把它設(shè)置為NULL,使用默認(rèn)屬性即可。同樣的,pthread_mutex_lock和pthread_mutex_unlock都是原子操作,如果一個線程調(diào)用pthread_mutex_lock試圖鎖住互斥量,而該互斥量,又被其他線程鎖住(占用),則該線程的pthread_mutex_lock調(diào)用就會阻塞,直到其他線程對該互斥量進(jìn)行解鎖,該線程才能獲得該互斥量,pthread_mutex_lock調(diào)用才會返回。
注意,使用互斥量的默認(rèn)屬性,如果程序試圖對一個已經(jīng)加鎖的互斥量調(diào)用pthread_mutex_lock,程序就會阻塞,而又因為擁有互斥量的這個線程正是現(xiàn)在被阻塞的線程,所以這個互斥量就永遠(yuǎn)不會被解鎖,也就是說,程序就會進(jìn)入死鎖的狀態(tài)。在使用時要多加注意,確保在同一個線程中,對加鎖的互斥再次進(jìn)行加鎖前要對其進(jìn)行解鎖。
三、使用互斥量進(jìn)行線程同步
下面以一個簡單的多線程程序來演示如何使用互斥量來進(jìn)行線程同步。在主線程中,我們創(chuàng)建子線程,并把數(shù)組msg作為參數(shù)傳遞給子線程,然后主線程調(diào)用函數(shù)pthread_mutex_lock對互斥量加鎖,等待輸入,輸入完成后,調(diào)用函數(shù)pthread_mutex_unlock對互斥量解鎖,從而使線程函數(shù)中的對互斥量加鎖的pthread_mutex_lock函數(shù)返回并執(zhí)行子線程中的代碼。線程函數(shù)在把字符串的小寫字母變成大寫并統(tǒng)計輸入的字符數(shù)量之后,它調(diào)用pthread_mutex_unlock對互斥量解鎖,使主線程能夠繼續(xù)獲得互斥量(即對其加鎖函數(shù)返回),再次執(zhí)行輸入功能直到主線程再次調(diào)用pthread_mutex_unlock對其解鎖,一直如此重復(fù),直到輸入end。
源文件為lockthread.c,源代碼如下: [cpp]?view plaincopyprint? #include?<unistd.h>?? #include?<pthread.h>?? #include?<stdlib.h>?? #include?<stdio.h>?? #include?<string.h>?? ?? ?? //聲明線程函數(shù)和互斥量?? void*?thread_func(void?*msg);?? pthread_mutex_t?mutex;?? ?? ?? #define?MSG_SIZE?512?? ?? ?? int?main()?? {?? ????int?res?=?-1;?? ????pthread_t?thread;?? ????void?*thread_result?=?NULL;?? ????char?msg[MSG_SIZE]?=?{'\0'};?? ????//初始化互斥量,使用默認(rèn)的互斥量屬性?? ????res?=?pthread_mutex_init(&mutex,?NULL);?? ????if(res?!=?0)?? ????{?? ????????perror("pthread_mutex_init?failed\n");?? ????????exit(EXIT_FAILURE);?? ????}?? ????//創(chuàng)建子線程,并把msg作為線程函數(shù)的參數(shù)傳遞給thread_func?? ????res?=?pthread_create(&thread,?NULL,?thread_func,?msg);?? ????if(res?!=?0)?? ????{?? ????????perror("pthread_create?failed\n");?? ????????exit(EXIT_FAILURE);?? ????}?? ????//輸入字符串,以串‘end’結(jié)束?? ????printf("Input?some?test.?Enter?'end'?to?finish\n");?? ????//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)?? ????pthread_mutex_lock(&mutex);?? ????while(strcmp("end\n",?msg)?!=?0)?? ????{?? ????????if(strncmp("TEST",?msg,?4)?==?0)?? ????????{?? ????????????strcpy(msg,?"copy_data\n");?? ????????}?? ????????else?? ????????{?? ????????????fgets(msg,?MSG_SIZE,?stdin);?? ????????}?? ????????//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)?? ????????pthread_mutex_unlock(&mutex);?? ????????sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會?? ????????pthread_mutex_lock(&mutex);?? ????}?? ????pthread_mutex_unlock(&mutex);?? ????printf("\nWaiting?for?thread?finish...\n");?? ????//等待子線程結(jié)束?? ????res?=?pthread_join(thread,?&thread_result);?? ????if(res?!=?0)?? ????{?? ????????perror("pthread_join?failed\n");?? ????????exit(EXIT_FAILURE);?? ????}?? ????printf("Thread?joined\n");?? ????//清理互斥量?? ????pthread_mutex_destroy(&mutex);?? ????exit(EXIT_SUCCESS);?? }?? void*?thread_func(void?*msg)?? {?? ????int?i?=?0;?? ????char?*ptr?=?msg;?? ????sleep(1);?? ????//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)?? ????pthread_mutex_lock(&mutex);?? ????while(strcmp("end\n",?msg)?!=?0)?? ????{?? ????????//把小寫字母變成大寫?? ????????for(i?=?0;?ptr[i]?!=?'\0';?++i)?? ????????{?? ????????????if(ptr[i]?>=?'a'?&&?ptr[i]?<='z')?? ????????????{?? ????????????????ptr[i]?-=?'a'?-?'A';?? ????????????}?? ????????}?? ????????printf("You?input?%d?characters\n",?i-1);?? ????????printf("To?uppercase:?%s\n",?ptr);?? ????????//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)?? ????????pthread_mutex_unlock(&mutex);?? ????????sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會?? ????????pthread_mutex_lock(&mutex);?? ????}?? ????pthread_mutex_unlock(&mutex);?? ????//退出線程?? ????pthread_exit(NULL);?? }??
運行結(jié)果如下:
程序分析:
這個程序的工作流程已經(jīng)說得非常清楚了,這里先來說說在main函數(shù)和線程函數(shù)thread_func中while循環(huán)中的sleep(1)語句的作用。可能很多人會認(rèn)為這個sleep(1)是為了讓子線程完成其處理和統(tǒng)計功能,所以要讓主線程休眠1秒鐘來等待子線程的處理統(tǒng)計工作的完成。的確在這里子線程進(jìn)行的工作十分簡單,1秒鐘內(nèi)的確可以處理統(tǒng)計完畢。但是這里的sleep(1)并不是為了實現(xiàn)這個功能,這兩個循環(huán)中的sleep(1)是為了讓其他的線程有機(jī)會被執(zhí)行到,如果在一次的加鎖和解鎖之間沒有這條語句的話,則當(dāng)前的線程將會一直在循環(huán)中獲得互斥量,因為其他的線程沒有執(zhí)行它的代碼的時間,所以就要用這樣的一條語句來給其他的線程一個運行的機(jī)會。如果子線程的執(zhí)行時間超過1秒,這個程序還是會正常運行。
以這個例子來說,在主線程中,當(dāng)輸入數(shù)據(jù)完畢并對互斥量解鎖之后,并不馬上循環(huán)對其加鎖,此時子線程就有了執(zhí)行的機(jī)會,它會對互斥量進(jìn)行加鎖,同樣地,當(dāng)它處理統(tǒng)計完輸入的數(shù)據(jù)后,它在進(jìn)入下一次循環(huán)前,也休眠1秒,讓主線程有機(jī)會再次運行。而主線程什么時候能夠執(zhí)行,取決于子線程何時對互斥量進(jìn)行解鎖。因為如果子線程擁有(鎖住)互斥量,則主線程中函數(shù)pthread_mutex_lock就不會返回,使主線程處于阻塞狀態(tài)。
換句話來說,就是只有子線程結(jié)束了對輸入的處理和統(tǒng)計后,主線程才能繼續(xù)執(zhí)行,向msg中寫入數(shù)據(jù)。看到這里,你應(yīng)該知道之前在使用信號量時,我們多用一個信號量也是為了達(dá)到這個目的。所以當(dāng)我們輸入TEST時,程序有兩個輸入,但還是能正常運行,同樣解決了之前使用一個信號量時所帶來的問題。
信號量和互斥量的作用都是保護(hù)代碼段的互斥設(shè)備,它們也非常相似。但在本例中,與使用信號量相比,實現(xiàn)同樣的功能,如果使用信號量的話,則需要兩個信號量,而使用互斥量的話,只需要一個。可以說在本例中,使用互斥量更簡單。但是我覺得使用互斥量更容易犯錯,我們可以看到在這個例子中,我們需要使用sleep語句來讓其他線程獲得執(zhí)行的機(jī)會,但是在使用信號量的程序,它并不需要使用sleep,相對來說比較直觀。我知道可能是我的實現(xiàn)方法不好,但是對于使用互斥量來說,我想了很久也想不到不使用sleep的方法。
undefined reference to 'pthread_create'
undefined reference to 'pthread_join'
問題解決:
??? 在編譯中要加 -lpthread參數(shù)
??? gcc thread.c -o thread -lpthread
??? thread.c為你些的源文件,不要忘了加上頭文件#include<pthread.h>
我自己的試驗例子 #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <string.h>//聲明線程函數(shù)和互斥量 void* thread_func(void *msg); pthread_mutex_t mutex;#define MSG_SIZE 512int main() {int res = -1;pthread_t thread;void *thread_result = NULL;char msg[MSG_SIZE] = {'\0'};//初始化互斥量,使用默認(rèn)的互斥量屬性res = pthread_mutex_init(&mutex, NULL);if(res != 0){perror("pthread_mutex_init failed\n");exit(EXIT_FAILURE);}//創(chuàng)建子線程,并把msg作為線程函數(shù)的參數(shù)傳遞給thread_funcres = pthread_create(&thread, NULL, thread_func, msg);if(res != 0){perror("pthread_create failed\n");exit(EXIT_FAILURE);}//輸入字符串,以串‘end’結(jié)束printf("Input some test. Enter 'end' to finish\n");//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)pthread_mutex_lock(&mutex);while(strcmp("end\n", msg) != 0){if(strncmp("TEST", msg, 4) == 0)/*輸入的msg是TEST*/{printf("www=============================test1\n");strcpy(msg, "copy_data\n");}else/*輸入的msg不是TEST*/{printf("www=============================test2\n");fgets(msg, MSG_SIZE, stdin);/*等待用戶輸入*/}//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)pthread_mutex_unlock(&mutex);sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會pthread_mutex_lock(&mutex);}pthread_mutex_unlock(&mutex);printf("\nWaiting for thread finish...\n");//等待子線程結(jié)束res = pthread_join(thread, &thread_result);if(res != 0){perror("pthread_join failed\n");exit(EXIT_FAILURE);}printf("Thread joined\n");//清理互斥量pthread_mutex_destroy(&mutex);exit(EXIT_SUCCESS); } void* thread_func(void *msg)/*子線程的功能是把主線程的傳下來的字母變成大寫字母*/ {int i = 0;char *ptr = msg;sleep(1);//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)pthread_mutex_lock(&mutex);while(strcmp("end\n", msg) != 0){//把小寫字母變成大寫for(i = 0; ptr[i] != '\0'; ++i){if(ptr[i] >= 'a' && ptr[i] <='z'){ptr[i] -= 'a' - 'A';}}printf("You input %d characters\n", i-1);printf("To uppercase: %s\n", ptr);//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)pthread_mutex_unlock(&mutex);sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會pthread_mutex_lock(&mutex);}pthread_mutex_unlock(&mutex);//退出線程pthread_exit(NULL); }
wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$ gcc muax.c -o muax -lpthread wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$ ./muax Input some test. Enter 'end' to finish www=============================test2 qqq You input 3 characters To uppercase: QQQwww=============================test2 TEST You input 4 characters To uppercase: TESTwww=============================test1 You input 9 characters To uppercase: COPY_DATAwww=============================test2 eee You input 3 characters To uppercase: EEEwww=============================test2 endWaiting for thread finish... Thread joined wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$
一、什么是互斥量
互斥量是另一種用于多線程中的同步訪問方法,它允許程序鎖住某個對象,使得每次只能有一個線程訪問它。為了控制對關(guān)鍵代碼的訪問,必須在進(jìn)入這段代碼之前鎖住一個互斥量,然后在完成操作之后解鎖。
二、互斥量的函數(shù)的使用
它們的定義與使用信號量的函數(shù)非常相似,它們的定義如下: [cpp]?view plaincopyprint?
pthread_mutex_init函數(shù)中的參數(shù)mutexattr指定互斥量的屬性,在這里我們并不關(guān)心互斥量的屬性,所以把它設(shè)置為NULL,使用默認(rèn)屬性即可。同樣的,pthread_mutex_lock和pthread_mutex_unlock都是原子操作,如果一個線程調(diào)用pthread_mutex_lock試圖鎖住互斥量,而該互斥量,又被其他線程鎖住(占用),則該線程的pthread_mutex_lock調(diào)用就會阻塞,直到其他線程對該互斥量進(jìn)行解鎖,該線程才能獲得該互斥量,pthread_mutex_lock調(diào)用才會返回。
注意,使用互斥量的默認(rèn)屬性,如果程序試圖對一個已經(jīng)加鎖的互斥量調(diào)用pthread_mutex_lock,程序就會阻塞,而又因為擁有互斥量的這個線程正是現(xiàn)在被阻塞的線程,所以這個互斥量就永遠(yuǎn)不會被解鎖,也就是說,程序就會進(jìn)入死鎖的狀態(tài)。在使用時要多加注意,確保在同一個線程中,對加鎖的互斥再次進(jìn)行加鎖前要對其進(jìn)行解鎖。
三、使用互斥量進(jìn)行線程同步
下面以一個簡單的多線程程序來演示如何使用互斥量來進(jìn)行線程同步。在主線程中,我們創(chuàng)建子線程,并把數(shù)組msg作為參數(shù)傳遞給子線程,然后主線程調(diào)用函數(shù)pthread_mutex_lock對互斥量加鎖,等待輸入,輸入完成后,調(diào)用函數(shù)pthread_mutex_unlock對互斥量解鎖,從而使線程函數(shù)中的對互斥量加鎖的pthread_mutex_lock函數(shù)返回并執(zhí)行子線程中的代碼。線程函數(shù)在把字符串的小寫字母變成大寫并統(tǒng)計輸入的字符數(shù)量之后,它調(diào)用pthread_mutex_unlock對互斥量解鎖,使主線程能夠繼續(xù)獲得互斥量(即對其加鎖函數(shù)返回),再次執(zhí)行輸入功能直到主線程再次調(diào)用pthread_mutex_unlock對其解鎖,一直如此重復(fù),直到輸入end。
源文件為lockthread.c,源代碼如下: [cpp]?view plaincopyprint?
程序分析:
這個程序的工作流程已經(jīng)說得非常清楚了,這里先來說說在main函數(shù)和線程函數(shù)thread_func中while循環(huán)中的sleep(1)語句的作用。可能很多人會認(rèn)為這個sleep(1)是為了讓子線程完成其處理和統(tǒng)計功能,所以要讓主線程休眠1秒鐘來等待子線程的處理統(tǒng)計工作的完成。的確在這里子線程進(jìn)行的工作十分簡單,1秒鐘內(nèi)的確可以處理統(tǒng)計完畢。但是這里的sleep(1)并不是為了實現(xiàn)這個功能,這兩個循環(huán)中的sleep(1)是為了讓其他的線程有機(jī)會被執(zhí)行到,如果在一次的加鎖和解鎖之間沒有這條語句的話,則當(dāng)前的線程將會一直在循環(huán)中獲得互斥量,因為其他的線程沒有執(zhí)行它的代碼的時間,所以就要用這樣的一條語句來給其他的線程一個運行的機(jī)會。如果子線程的執(zhí)行時間超過1秒,這個程序還是會正常運行。
以這個例子來說,在主線程中,當(dāng)輸入數(shù)據(jù)完畢并對互斥量解鎖之后,并不馬上循環(huán)對其加鎖,此時子線程就有了執(zhí)行的機(jī)會,它會對互斥量進(jìn)行加鎖,同樣地,當(dāng)它處理統(tǒng)計完輸入的數(shù)據(jù)后,它在進(jìn)入下一次循環(huán)前,也休眠1秒,讓主線程有機(jī)會再次運行。而主線程什么時候能夠執(zhí)行,取決于子線程何時對互斥量進(jìn)行解鎖。因為如果子線程擁有(鎖住)互斥量,則主線程中函數(shù)pthread_mutex_lock就不會返回,使主線程處于阻塞狀態(tài)。
換句話來說,就是只有子線程結(jié)束了對輸入的處理和統(tǒng)計后,主線程才能繼續(xù)執(zhí)行,向msg中寫入數(shù)據(jù)。看到這里,你應(yīng)該知道之前在使用信號量時,我們多用一個信號量也是為了達(dá)到這個目的。所以當(dāng)我們輸入TEST時,程序有兩個輸入,但還是能正常運行,同樣解決了之前使用一個信號量時所帶來的問題。
信號量和互斥量的作用都是保護(hù)代碼段的互斥設(shè)備,它們也非常相似。但在本例中,與使用信號量相比,實現(xiàn)同樣的功能,如果使用信號量的話,則需要兩個信號量,而使用互斥量的話,只需要一個。可以說在本例中,使用互斥量更簡單。但是我覺得使用互斥量更容易犯錯,我們可以看到在這個例子中,我們需要使用sleep語句來讓其他線程獲得執(zhí)行的機(jī)會,但是在使用信號量的程序,它并不需要使用sleep,相對來說比較直觀。我知道可能是我的實現(xiàn)方法不好,但是對于使用互斥量來說,我想了很久也想不到不使用sleep的方法。
undefined reference to 'pthread_create'
undefined reference to 'pthread_join'
問題解決:
??? 在編譯中要加 -lpthread參數(shù)
??? gcc thread.c -o thread -lpthread
??? thread.c為你些的源文件,不要忘了加上頭文件#include<pthread.h>
我自己的試驗例子 #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <string.h>//聲明線程函數(shù)和互斥量 void* thread_func(void *msg); pthread_mutex_t mutex;#define MSG_SIZE 512int main() {int res = -1;pthread_t thread;void *thread_result = NULL;char msg[MSG_SIZE] = {'\0'};//初始化互斥量,使用默認(rèn)的互斥量屬性res = pthread_mutex_init(&mutex, NULL);if(res != 0){perror("pthread_mutex_init failed\n");exit(EXIT_FAILURE);}//創(chuàng)建子線程,并把msg作為線程函數(shù)的參數(shù)傳遞給thread_funcres = pthread_create(&thread, NULL, thread_func, msg);if(res != 0){perror("pthread_create failed\n");exit(EXIT_FAILURE);}//輸入字符串,以串‘end’結(jié)束printf("Input some test. Enter 'end' to finish\n");//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)pthread_mutex_lock(&mutex);while(strcmp("end\n", msg) != 0){if(strncmp("TEST", msg, 4) == 0)/*輸入的msg是TEST*/{printf("www=============================test1\n");strcpy(msg, "copy_data\n");}else/*輸入的msg不是TEST*/{printf("www=============================test2\n");fgets(msg, MSG_SIZE, stdin);/*等待用戶輸入*/}//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)pthread_mutex_unlock(&mutex);sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會pthread_mutex_lock(&mutex);}pthread_mutex_unlock(&mutex);printf("\nWaiting for thread finish...\n");//等待子線程結(jié)束res = pthread_join(thread, &thread_result);if(res != 0){perror("pthread_join failed\n");exit(EXIT_FAILURE);}printf("Thread joined\n");//清理互斥量pthread_mutex_destroy(&mutex);exit(EXIT_SUCCESS); } void* thread_func(void *msg)/*子線程的功能是把主線程的傳下來的字母變成大寫字母*/ {int i = 0;char *ptr = msg;sleep(1);//把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據(jù)pthread_mutex_lock(&mutex);while(strcmp("end\n", msg) != 0){//把小寫字母變成大寫for(i = 0; ptr[i] != '\0'; ++i){if(ptr[i] >= 'a' && ptr[i] <='z'){ptr[i] -= 'a' - 'A';}}printf("You input %d characters\n", i-1);printf("To uppercase: %s\n", ptr);//把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據(jù)pthread_mutex_unlock(&mutex);sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機(jī)會pthread_mutex_lock(&mutex);}pthread_mutex_unlock(&mutex);//退出線程pthread_exit(NULL); }
wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$ gcc muax.c -o muax -lpthread wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$ ./muax Input some test. Enter 'end' to finish www=============================test2 qqq You input 3 characters To uppercase: QQQwww=============================test2 TEST You input 4 characters To uppercase: TESTwww=============================test1 You input 9 characters To uppercase: COPY_DATAwww=============================test2 eee You input 3 characters To uppercase: EEEwww=============================test2 endWaiting for thread finish... Thread joined wqf@wqf-System-Product-Name:/worksen/lddexamples/muax$
總結(jié)
以上是生活随笔為你收集整理的Linux多线程——使用互斥量同步线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: basler相机参数简要中文说明_Bas
- 下一篇: linux 其他常用命令