线程安全之strtok()函数
先來看下線程安全的概念:
 ????????線程安全是多線程編程時的計算機程序代碼中的一個概念。在擁有共享數據的多條線程并行執行的程序中,線程安全的代碼會通過同步機制保證各個線程都可以正常且正確的執行,不會出現數據污染等意外情況。
 
通俗來講,就是當多線程運行的時候,運行結果和你預想的結果有一定的偏差的話,就會造成線程安全的問題。先來看下面一段代碼:
它的代碼實現的功能是主線程創建一個子線程,主線程對abc分隔打印,子線程對123進行分割打印,當讓對于子線程和主線程并發執行,所以最后打印結果可能會有交叉1a2b這種結果這是無所謂的,下面就讓我們來看一下運行結果:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>void * fun(void * arg)
{char arr[128] = "1 2 3 4 5 6 7 8";char *s = strtok(arr," ");while(s != NULL){printf("fun s = %s \n",s);s = strtok(NULL," ");}
}int main()
{pthread_t id;pthread_create(&id,NULL,fun,NULL);char buff[128] = "a b c d e f g h";char *s = strtok(buff," ");while(s != NULL){printf("main s = %s \n",s);s = strtok(NULL," ");}pthread_join(id,NULL);exit(0);
} 
運行結果如下:
?執行結果如上所示,為什么會出現這種情況呢,明明我們的代碼沒有寫錯,原因就在strtok的底層那塊出問題了:
char *strtok(char *str, const char *delim)
底層實現大家可以去看這篇博客對于strtok底層的實現(個人觀念)_YearnZhu的博客-CSDN博客
底層維護的是一塊靜態靜態內存區域,因為strtok連續調用靜態內存區域來對字符串進行分割。靜態變量只初始化一次,在主線程執行一次之后因為是靜態變量,所以會記住它分割的位置,但是這時候子線程又傳入了數組arr,然后子線程執行一次就會把分割位置的標記轉到arr中,所以就會有主線程打印出子線程中的分割結果。
?
這里在各大家補充一下,什么是重入性:
????????可重入(reentrant)函數可以由多于一個任務并發使用,而不必擔心數據錯誤。相反,不可重入(non-reentrant)函數不能由超過一個任務所共享,除非能確保函數的互斥(或者使用信號量,或者在代碼的關鍵部分禁用中斷)。可重入函數可以在任意時刻被中斷,稍后再繼續運行,不會丟失數據。可重入函數要么使用本地變量,要么在使用全局變量時保護自己的數據。
可重入函數:
 (1)不為連續的調用持有靜態數據。
 (2)不返回指向靜態數據的指針;所有數據都由函數的調用者提供。
 (3)使用本地數據,或者通過制作全局數據的本地拷貝來保護全局數據。
 (4)如果必須訪問全局變量,記住利用互斥信號量來保護全局變量。
 (5)絕不調用任何不可重入函數。
那么解決方法是什么呢,使用線程安全函數strtok_r()
strtok_r(char* s, const char* delm, char** context)
前兩個參數和strtok中一樣,第三個參數就是上次分割剩余字符的地址!
下面來看修改完的代碼:(凡是有改動的地方都有代碼注釋)
 ?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>void * fun(void * arg)
{char arr[128] = "1 2 3 4 5 6 7 8";char *ptr = NULL;                       //所加的代碼char *s = strtok_r(arr," ",&ptr);       //&ptr這塊是二級指針,所以得有&while(s != NULL){printf("fun s = %s \n",s);        s = strtok_r(NULL," ",&ptr);          //&ptr這塊是二級指針,所以得有&}
}int main()
{pthread_t id;pthread_create(&id,NULL,fun,NULL);char buff[128] = "a b c d e f g h";char *ptr = NULL;                  //所加的代碼char *s = strtok_r(buff," ",&ptr);   //&ptr這塊是二級指針,所以得有&while(s != NULL){printf("main s = %s \n",s);s = strtok_r(NULL," ",&ptr);    //&ptr這塊是二級指針,所以得有&}pthread_join(id,NULL);exit(0);
} 
下面來看運行結果:
?上面說到了,因為并發執行,難免會有交差現象,這是正常的,所以上面代碼運行結果就達到了我們的預期!
總結
以上是生活随笔為你收集整理的线程安全之strtok()函数的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: “况当故园夜”下一句是什么
 - 下一篇: Linux多线程的同步------读写锁