北京電子科技學院(BESTI)linux
實驗報告ios
課程:信息安全系統設計基礎 班級:1353算法
姓名:蘆暢 傅冬菁數組
學號:20135308 20135311緩存
成績: 指導教師:婁家鵬 實驗日期:2015.11.10安全
實驗密級: 預習程度: 實驗時間:15:30~18:00多線程
儀器組次: 必修/選修: 實驗序號:2異步
實驗名稱:實驗二:固件設計函數
實驗目的與要求:測試
1.掌握程序的燒寫方法;
2.可以實現Bootloader;
3.實現密碼學中常見算法的固化。
實驗儀器:
名稱 |
型號 |
數量 |
嵌入式開發平臺 |
UP-NETARM2410-CL |
1 |
PC機 |
DELL |
1 |
實驗內容、步驟與體會:
1.開發環境的配置同實驗一。
2.將實驗代碼拷貝到共享文件夾中。
3.在虛擬機中編譯代碼。
輸入命令:armv4l-unknown-linux-gcc pthread.c -o pthread -lpthread
對於多線程相關的代碼,編譯時須要加-lpthread的庫。
編譯成功。
4.下載調試
在超級終端中運行可執行文件pthread,可得實驗結果以下所示。
運行可執行文件term。
執行term時出現下面的錯誤:
/dev/ttyS0: No such file or directory
能夠經過創建一個鏈接來解決。
在超級終端中進入/dev文件夾中。
輸入命令「ln –sf /dev/tts/0 /dev/ttyS0」
由於在 Linux 下串口文件位於/dev 下,通常在老版本的內核中串口一爲/dev/ttyS0 ,串口二爲 /dev/ttyS1, 在咱們的開發板中串口設備位於/dev/tts/下,由於開發板中沒有ttyS0這個設備,因此咱們要創建一個鏈接。
實驗分析:
(一)進程相關函數
線程在運行過程當中須要和其餘線程進行交互,在資源不能知足時,須要暫時掛起以等待其餘線程正在使用的資源。這種機制稱爲線程之間同步。線程同步的方法主要有互斥鎖、條件變量和信號量。
1.建立進程
建立線程:pthread_create 頭文件:#include<pthread.h> 函數原型:int pthread_create(pthread_t *thread,pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
獲取線程ID:pthread_self 頭文件:#include<pthread.h> 函數原型:pthread_t pthread_self(void);
判斷2個線程ID是否指向同一線程:pthread_equal 頭文件:#include<pthread.h> 函數原型:int pthread_equal(pthread_t thread1,pthread_t thread2);
用於保證init_routine(本身建立的線程)線程函數在進程中僅調用一次,沒法再此調用:pthread_once 頭文件:#include<pthread.h> 函數原型:int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));
2.終止進程
線程終止:pthread_exit 頭文件:#include<pthread.h> 函數原型:void pthread_exit(void *retval);
用於自動釋放資源函數:pthread_cleanup_push(),pthread_cleanup_pop() 頭文件:#include<pthread.h> 函數原型:#define pthread_cleanup_push(routine,arg)\ {struct _pthread_cleanup_buffer buffer;\ _pthread_cleanup_push(&buffer,(routine),(srg)); #define pthread_cleanup_pop\ _pthread_clean_pop(&buffer,(exeute)); }
等待一個線程結束的函數:pthread_join 頭文件:#include<pthread.h> 函數原型:int pthread_join(pthread_t th,void *thread_return);
3.私用數據
建立一個鍵:pthread_key_create 頭文件:#include<pthread.h> 函數原型:int pthread_key_create(pthread_key_t *key,void(*destr_function)(void *));
爲一個鍵設置使用數據: 頭文件:#include<pthread.h> 函數原型:int pthread_setspecific(pthread_key_t key,(const void *pointer));
讀取一個鍵的私有數據:pthread_getspecific 頭文件:#include<pthread.h> 函數原型:void *pthread_getspecific(pthread_key_t key);
刪除一個鍵:pthread_key_delete 頭文件:#include<pthread.h> 函數原型:int pthread_key_delete(pthread_key_t key);
4.互斥鎖
線程在運行過程當中須要使用共享資源時,要保證該線程獨佔該資源,之中機制稱爲互斥。
方法是:在某線程須要訪問共享資源時,就對其加鎖,使用完後再釋放鎖。
初始化一個互斥鎖:pthread_mutex_init 頭文件:#include<pthread.h> 函數原型:int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);
註銷一個互斥鎖:pthread_mutex_destory 頭文件:#include<pthread.h> 函數原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
加鎖,若是不成功,阻塞等待:pthread_mutex_lock 頭文件:#include<pthread.h> 函數原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
解鎖:pthread_mutex_unlock 頭文件:#include<pthread.h> 函數原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
5.條件變量
條件變量經過容許線程阻塞和等待另外一線程發送信號的方法彌補了互斥鎖的不足,它常與互斥鎖一塊兒使用。
在使用時,條件變量被用來阻塞一個線程,當條件不知足時,線程每每解開互斥鎖並等待條件發生變化。一旦其餘線程改變了條件變量,就將通知相應的條件變量喚醒一個或多個正被該條件變量阻塞的線程。被喚醒的線程將從新鎖定互斥鎖並測試條件是否知足。
初始化條件變量:pthread_cond_init 頭文件:#include<pthread.h> 函數原型:int pthread_cond_t cond=PTHREAD_COND_INITIALIZER; int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
基於條件變量阻塞,無條件等待:pthread_cond_wait 頭文件:#include<pthread.h> 函數原型:int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
阻塞直到指定事件發生,計時等待:pthread_cond_timedwait 頭文件:#include<pthread.h> 函數原型:int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *abstime);
解除特定線程的阻塞,存在多個等待線程時按入隊順序激活其中一個:pthread_cond_signal 頭文件:#include<pthread.h> 函數原型:int pthread_cond_signal(pthread_cond_t *cond);
解除全部線程的阻塞:pthread_cond_broadcast 頭文件:#include<pthread.h> 函數原型:int pthread_cond_broadcast(pthread_cond_t *cond);
清除條件變量:pthread_cond_destroy 頭文件:#include<pthread.h> 函數原型:int pthread_cond_destroy(pthread_cond_t *cond);
6.異步信號
信號量本質上市一個非負的整數計數器,能夠控制對公共資源的訪問,其數據類型爲sem_t,對應的頭文件爲semaphore.h
用來向特定線程發送信號:pthread_kill 頭文件#include<pthread.h> 函數原型:int pthread_kill(pthread_t threadid,int signo);
設置線程的信號屏蔽碼:pthread_sigmask(但對不容許屏蔽的Cancel信號和不容許響應的Restart信號進行了保護) 頭文件#include<pthread.h> 函數原型:int pthread_sigmask(int how,const sigset_t *newmask,sigset_t *oldmask);
阻塞線程:sigwait 頭文件#include<pthread.h> 函數原型:int sigwait (const sigset_t *set,int *sig);
(二)實驗代碼分析
#include <stdio.h> #include <stdlib.h> #include <time.h> #include "pthread.h" #define BUFFER_SIZE 16 /* 設置一個整數的循環緩衝區。 */ struct prodcons { int buffer[BUFFER_SIZE]; /* 緩存區數組 */ pthread_mutex_t lock; /* 互斥鎖:互斥保證緩衝區的互斥訪問 */ int readpos, writepos; /* 讀寫的位置 */ pthread_cond_t notempty; /* 當緩衝區沒有空信號*/ pthread_cond_t notfull; /* 當緩衝區沒有滿信號 */ }; /*--------------------------------------------------------*/ /* 初始化緩衝區 */ void init(struct prodcons * b) { pthread_mutex_init(&b->lock, NULL); pthread_cond_init(&b->notempty, NULL); pthread_cond_init(&b->notfull, NULL); b->readpos = 0; b->writepos = 0; } /*--------------------------------------------------------*/ /*在存儲緩衝區中寫入整數*/ void put(struct prodcons * b, int data) { pthread_mutex_lock(&b->lock); /* 等待緩衝區非滿 */ while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) { printf("wait for not full\n"); pthread_cond_wait(&b->notfull, &b->lock); } /* 寫入數據,並提早寫指針*/ b->buffer[b->writepos] = data; b->writepos++; /* 緩衝區指針加1*/
if (b->writepos >= BUFFER_SIZE) b->writepos = 0; /* 信號緩衝區此時非空 */ pthread_cond_signal(&b->notempty);/* 發緩衝區不空信號 */ pthread_mutex_unlock(&b->lock); } /*--------------------------------------------------------*/ /* 讀取並從緩衝區中刪除一個整數 */ int get(struct prodcons * b) { int data; pthread_mutex_lock(&b->lock); /* 等待緩衝非空 */ while (b->writepos == b->readpos) { printf("wait for not empty\n"); pthread_cond_wait(&b->notempty, &b->lock); } /*讀取數據並提早讀取指針*/ data = b->buffer[b->readpos]; b->readpos++;
/*讀取指針加1*/
if (b->readpos >= BUFFER_SIZE) b->readpos = 0; /* 信號緩衝區如今非滿*/ pthread_cond_signal(&b->notfull); pthread_mutex_unlock(&b->lock); return data; } /*--------------------------------------------------------*/ #define OVER (-1) struct prodcons buffer; /*--------------------------------------------------------*/ void * producer(void * data) { int n; for (n = 0; n < 1000; n++) { printf(" put-->%d\n", n); put(&buffer, n); } put(&buffer, OVER); printf("producer stopped!\n"); return NULL; } /*--------------------------------------------------------*/ void * consumer(void * data) { int d; while (1) { d = get(&buffer); if (d == OVER ) break; printf(" %d-->get\n", d); } printf("consumer stopped!\n"); return NULL; } /*--------------------------------------------------------*/ int main(void) { pthread_t th_a, th_b; void * retval; init(&buffer); pthread_create(&th_a, NULL, producer, 0); pthread_create(&th_b, NULL, consumer, 0); /*等待生產者和消費者的結束。*/ pthread_join(th_a, &retval); pthread_join(th_b, &retval); return 0; }
串口通訊分析
fd=open("/dev/ttyS1",O_NOCTTY|O_RDWR|O_NONBLOCK); if( fd < 0) { perror("Unable open /dev/ttyS0\r "); return 1; }
這是文件I/O的經常使用函數,open函數,open函數用來打開一個設備,他返回的是一個整型變量,若是這個值等於-1,說明打開文件出現錯誤,若是爲大於0的值,那麼這個值表明的就是文件描述符。
這個事經常使用的一種用法fd是設備描述符,linux在操做硬件設備時,屏蔽了硬件的基本細節,只把硬件當作文件來進行操做,而全部的操做都是以open函數來開始,它用來獲取fd,而後後期的其餘操做所有控制fd來完成對硬件設備的實際操做。
O_RDWR 讀寫方式打開;
O_NOCTTY 不容許進程管理串口(不太理解,通常都選上);
O_NDELAY 非阻塞(默認爲阻塞,打開後也可使用fcntl()從新設置)
經常使用串口操做
寫入:n = write(fd, "linux", 5); n實際寫入字節數; 讀取:res = read(fd,buf,len); res 讀取的字節數; 設置:fcntl(fd, F_SETFL, FNDELAY); //非阻塞 fcntl(fd, F_SETFL, 0); // 阻塞 關閉:close(fd);
串口設置
struct termios options; // 串口配置結構體 tcgetattr(fd,&options); //獲取當前設置 bzero(&options,sizeof(options)); options.c_cflag |= B115200 | CLOCAL | CREAD; // 設置波特率,本地鏈接,接收使能 options.c_cflag &= ~CSIZE; //屏蔽數據位 options.c_cflag |= CS8; // 數據位爲 8 ,CS7 for 7 options.c_cflag &= ~CSTOPB; // 一位中止位, 兩位中止爲 |= CSTOPB options.c_cflag &= ~PARENB; // 無校驗 //options.c_cflag |= PARENB; //有校驗 //options.c_cflag &= ~PARODD // 偶校驗 //options.c_cflag |= PARODD // 奇校驗 options.c_cc[VTIME] = 0; // 等待時間,單位百毫秒 (讀)。後有詳細說明 options.c_cc[VMIN] = 0; // 最小字節數 (讀)。後有詳細說明 tcflush(fd, TCIOFLUSH); // TCIFLUSH刷清輸入隊列。 TCOFLUSH刷清輸出隊列。 TCIOFLUSH刷清輸入、輸出隊列。 tcsetattr(fd, TCSANOW, &options); // TCSANOW當即生效; TCSADRAIN:Wait until everything has been transmitted; TCSAFLUSH:Flush input and output buffers and make the change
1.打開串口函數open_port()中要實現的函數: (1)open("/dev/ttys0",O_RDWR | O_NOCTTY | O_NDELAY);/*打開串口0*/ (2)fcntl(fd,F_SETFL,0)/*恢復串口爲阻塞狀態*/ (3)isatty(STDIN_FILENO) /*測試是否爲中斷設備 非0便是中斷設備*/ 2.配置串口參數函數set_opt()中要實現的函數: (1)保存原先有串口配置 tcgetattr(fd,&oldtio); (2)先將新串口配置清0 bzore(&newtio,sizeof(newito)); (3)激活選項CLOCAL和CREAD 並設置數據位大小 newtio.c_cflag |=CLOCAL | CREAD; newtio.c_cflag &= ~CSIZE; newtio.c_cflag |=CS8; (4)設置奇偶校驗 奇校驗: newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); 偶校驗: newtio.c_iflag |= (INPCK | ISTRIP); newtio.c_cflag |= PAREND; newtio.c_cflag &= ~PARODD; 無奇偶校驗: newtio.c_cflag &= ~PARENB; (5) 設置中止位 newtio.c_cflag &= ~CSTOPB; /*中止位爲1*/ newtio.c_cflag |= CSTOPB;/*中止位爲0*/ (6)設置波特率: cfsetispeed(&newtio,B115200); cfsetospeed(&newtio,B115200); (7)設置等待時間和最小接受字符: newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; (8)處理爲接收字符: tcflush(fd,TCIFLUSH); (9)激活新配置: tcsetattr(fd,TCSANOW,&newtio); 3.讀寫串口 write(fd,buff,8); read(fd,buff,8);
遇到的問題及解決:
實驗二在實驗一環境搭建下進行得很順利,直到最後一步,一直不成功,應該是沒有輸入正確命令,要嚴格到每個空格,大小寫徹底相同,後來嘗試了幾遍後終於成功了。
通過查閱資料,我明白:串行端口終端(Serial Port Terminal)是使用計算機串行端口鏈接的終端設備。計算機把每一個串行端口都看做是一個字符設備。有段時間這些串行端口設備一般被稱爲終端設備,由於 那時它的最大用途就是用來鏈接終端。這些串行端口所對應的設備名稱是/dev/tts/0(或/dev/ttyS0), /dev/tts/1(或/dev/ttyS1)等,設備號分別是(4,0), (4,1)等,分別對應於DOS系統下的COM一、COM2等。若要向一個端口發送數據,能夠在命令行上把標準輸出重定向到這些特殊文件名上便可。例如, 在命令行提示符下鍵入:echo test > /dev/ttyS1會把單詞」test」發送到鏈接在ttyS1(COM2)端口的設備上。