关于可重入函数

xt646449830 2012-05-11 02:21:11
满足下列条件的函数多数是不可重入的:
  1) 函数体内使用了静态的数据结构;
  2) 函数体内调用了malloc()或者free()函数;
  3) 函数体内调用了标准I/O函数。

对于1很容易理解,2我就不懂了,3的话应该是有缓冲区,大家聊聊
...全文
466 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
rendao0563 2012-06-11
  • 打赏
  • 举报
回复
环境都不确定的情况 这个问题怎么讨论?
独孤过儿 2012-05-17
  • 打赏
  • 举报
回复
可重入和线程安全是两回事,OK?
赵4老师 2012-05-17
  • 打赏
  • 举报
回复
core就是进程意外退出,操作系统可能生成对应的core内存转储文件,方便使用调试工具加载此文件用于尽可能再现进程意外退出前的进程状态,进一步发现导致进程意外退出的原因。
xt646449830 2012-05-17
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]

引用 9 楼 的回复:
引用 6 楼 的回复:

引用 2 楼 的回复:

2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.

===
mallo……
[/Quote]什么叫core
  • 打赏
  • 举报
回复
发现在研究某个问题的时候经常性发现偏题 或者 钻进死胡同;
我的理解:
可重入即某个函数在同时进入时的执行并不相互影响。
线程安全主要实现了对共享资源的访问冲突问题的解决。


为啥大家常常可重入和线程安全联系在一起呢?因为多线程执行同一个函数,很容易模拟可重入中指的函数的同时被调用执行;重入也可以只同一个线程中中发生。

举个例子:即使你对函数内资源使用了互斥锁,保证了多个线程不会同时进入,但是同一个线程互斥锁就起不到作用了。(关于这个互斥锁我测试了下)

//EnterCriticalSection(&cs);并不能阻止重入
DWORD WINAPI fun(LPVOID lparam)
{
EnterCriticalSection(&cs);
fun(0);
//LeaveCriticalSection(&cs);
return 0;
}


但我自己感觉还没说到点子,就拿malloc来说,如果函数中含有malloc正在处理,而来了一个信号,转入信号执行,如果信号执行也是用malloc则肯定会出现意想不到的错误。(PS:这个想法的前提是,对malloc中资源加的锁和上述fun中锁出现同样的效果,即同一线程中互斥锁并不能阻止再次访问共享资源)

我也是刚深入这个概念,并且搜索了相关一些论坛讨论和资料,总结出的一点个人看法,可以一起讨论讨论。
  • 打赏
  • 举报
回复
对线程安全和可重入我也进行了相关的阅读,确实是个不错的问题:
最后看了个chinaunix的帖子,讨论的还算不错,楼主可以看下:
http://bbs.chinaunix.net/thread-942090-6-1.html
mLee79 2012-05-17
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

可重入和线程安全是两回事,OK?
[/Quote]

这个正解, malloc/free/printf 可以是线程安全的, 但都不是可重入的...
赵4老师 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
就是即使在A函数被调用没返回之前A函数中某个功能可能直接或间接调用了A也不会扰乱A的功能。
[/Quote]
补充:
还有即使在A函数被调用没返回之前另一个线程可能也开始调用A也不会扰乱A的功能。
赵4老师 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]
引用 6 楼 的回复:

引用 2 楼 的回复:

2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.

===
malloc不知道,但是printf显然……
[/Quote]
不会core但可能会乱。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define _vsnprintf vsnprintf
#endif
//Log{
#define MAXLOGSIZE 100000000
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
char logstr[16000];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
#else
void Lock(CRITICAL_SECTION *l) {
pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
pthread_mutex_unlock(l);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb;

if (NULL==pszFmt||0==pszFmt[0]) return;
if (-1==_vsnprintf(logstr,ARRSIZE(logstr),pszFmt,argp)) logstr[ARRSIZE(logstr)-1]=0;
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
flog=fopen(logfilename1,"a");
if (NULL==flog) return;
}
fclose(flog);
}
}
void Log(const char *pszFmt,...) {
va_list argp;

Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
int main(int argc,char * argv[]) {
int i;
#ifdef WIN32
InitializeCriticalSection(&cs_log);
#else
pthread_mutex_init(&cs_log,NULL);
#endif
for (i=0;i<10000;i++) {
Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);
}
#ifdef WIN32
DeleteCriticalSection(&cs_log);
#else
pthread_mutex_destroy(&cs_log);
#endif
return 0;
}
nice_cxf 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

引用 6 楼 的回复:

引用 2 楼 的回复:

2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.

===
malloc不知道,但是print……
[/Quote]
我想重入我们的理解大概不一样,不是dump才叫不可重入,输出出错一样不行,多个线程同时printf输出有时会错乱的,我认为这就是不可重入
恨天低 2012-05-11
  • 打赏
  • 举报
回复
printf应该是线程安全的
qq120848369 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

引用 2 楼 的回复:

2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.

===
malloc不知道,但是printf显然不是线程安全的是不可重入的……
[/Quote]

你落伍了,这个问题我老早就已经深入调研过了,C库是支持多线程版本的,而且一般都是默认的。
不信的话可以跑1000个线程,都用printf操作stdout,你看会不会core?
赵4老师 2012-05-11
  • 打赏
  • 举报
回复
就是即使在A函数被调用没返回之前A函数中某个功能可能直接或间接调用了A也不会扰乱A的功能。
酱油党 2012-05-11
  • 打赏
  • 举报
回复
那啥,我外星人了,谁解释下你们所说的重入是什么概念?是重复调用还是什么?
nice_cxf 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.
[/Quote]
===
malloc不知道,但是printf显然不是线程安全的是不可重入的
Yaozhx 2012-05-11
  • 打赏
  • 举报
回复
申请完了突然中断了谁来释放啊
ZPH2254 2012-05-11
  • 打赏
  • 举报
回复
百度百科:

可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。
W170532934 2012-05-11
  • 打赏
  • 举报
回复
第三个就是I/O也是全局的哇。调用I/O的话那就修改了全局的状态了呢。
qq120848369 2012-05-11
  • 打赏
  • 举报
回复
2,malloc/free早就安全了,否则程序都没法写了。
3,这个一般也安全了,可以看一下printf源码,内部操作FILE* buffer的位置被被加锁了,需要编译c库时候选个什么玩意的,建议考虑安全性与输出的有序性,还是在底层API的基础上封一层带互斥锁的版本为多线程服务.
www_adintr_com 2012-05-11
  • 打赏
  • 举报
回复
malloc 的实现使用了全局变量, 违反第一条

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧