线程安全与可重入函数strtok_r()

来源:互联网 发布:网络爬虫的目的和意义 编辑:程序博客网 时间:2024/06/18 03:58

一、线程安全
一个函数被称为线程安全的(thread-safe),当且仅当被多个并发进程反复调用时,它会一直产生正确的结果。如果一个函数不是线程安全的,我们就说它是线程不安全的(thread-unsafe)。

例如:
要在主线程中根据空格分隔char buff[]=”1 2 3 4 5 6 7 8 9 0”;,并将分隔的数据输出,每隔1S中分一次,同样在函数线程中分隔char buff[]=”a b c d e f g h i j k”;并将分隔的数据输出,每隔1S中分一次。

代码示例:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <unistd.h>#include <pthread.h>void *fun(void *arg){    char buff[]="a b c d e f g h i j k";    char *tmp=strtok(buff," ");    while(tmp)    {        printf("%s",tmp);        sleep(1);        tmp=strtok(NULL," ");    }}void main(){    pthread_t th;    int res=pthread_create(&th,NULL,fun,NULL);    assert(res==0);    char buff[]="1 2 3 4 5 6 7 8 9 0";    char *tmp=strtok(buff," ");    while(tmp)    {        printf("%s",tmp);        sleep(1);        tmp=strtok(NULL," ");    }}打印结果为:1 a b c d e f g h i g k 

分析:打印只打印了 主线程中的1,而没有打印其他字符串,是因为字符存储在栈区,而当函数结束,字符区域会被释放掉,再进入到主线程,传NULL,没有字符可分隔,但将函数线程的字符分隔,所以应该将字符数组放到全局变量区,但是放在全局变量是不安全的。

所以为了实现全部字符的分割,此处便引进了可重入函数。

二、可重入函数
可重入函数是线程安全函数的一种,其特点在于它们被多个线程调用时,不会引用任何共享数据。
可重入函数通常要比不可重入的线程安全函数效率高一些,因为它们不需要同步操作。

1、一个可重入函数需要满足的是:

a、不使用全局变量或静态变量;
b、不使用用malloc或者new开辟出的空间;
c、不调用不可重入函数;
d、不返回静态或全局数据,所有数据都有函数的调用者提供;
e、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;

2、不可重入特点

如果一个函数符合以下条件之一的,则是不可重入的:

(1)调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的。
(2)调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
(3)可重入体内使用了静态的数据结构。

对于以上问题进行解决:运用strtok_r可重入函。
代码示例:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <unistd.h>#include <pthread.h>void *fun(void *arg){    char buff[]="a b c d e f g h i j k";    char *q=NULL;    char *tmp=strtok_r(buff," ",&q);    while(tmp)    {        printf("%s",tmp);        sleep(1);        tmp=strtok_r(NULL," ",&q);    }}void main(){    pthread_t th;    int res=pthread_create(&th,NULL,fun,NULL);    assert(res==0);    char buff[]="1 2 3 4 5 6 7 8 9 0";    char *q=NULL;    char *tmp=strtok_r(buff," ",&q);    while(tmp)    {        printf("%s",tmp);        sleep(1);        tmp=strtok_r(NULL," ",&q);    }}打印结果:a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 0 k; 
原创粉丝点击