level 6
肃然且通亮的雏菊2
楼主
[Win7 vs2010]
Q: C库和系统api之间是什么关系? A: 如下图,简单示意:

可以看出,C库一部分是使用系统api实现自身功能(比如文件操作),另一部分并不会直接依赖系统api,单独实现功能(比如字符串处理)。另外,对于驱动模块,按照不同的理解,也可以放入操作系统内部或者操作系统下层;如果把操作系统看成隐形的CPU和内存的驱动,那么它也可以看成和常规意义的硬件驱动是平级的。而,C库,从理论上来说,没必要和驱动有依赖关系。当然,访问操作系统的方式不仅仅是它提供的api,也是可以通过其它方式来访问。
Q:c库和多线程到底什么关系? A: 多线程在操作系统上的运用导致了很多库,包括之前的单线程版本的c库,也必须做出相应修改,才能保证运行不会出现问题。例如,如下是vs2010附带的fgets.c中部分源代码: [cpp] view plaincopy
_TSCHAR * __cdecl _fgetts (
_TSCHAR *string,
int count,
FILE *str
)
{
REG1 FILE *stream;
REG2 _TSCHAR *pointer = string;
_TSCHAR *retval = string;
int ch;
_VALIDATE_RETURN(( string != NULL ) || ( count == 0 ), EINVAL, NULL);
_VALIDATE_RETURN(( count >= 0 ), EINVAL, NULL);
_VALIDATE_RETURN(( str != NULL ), EINVAL, NULL);
if (count == 0)
{
return NULL;
}
/* The C Standard states the input buffer should remain
unchanged if EOF is encountered immediately. Hence we
do not blank out the input buffer here */
/* Init stream pointer */
stream = str;
_lock_str(stream);
__try {
#ifndef _UNICODE
_VALIDATE_STREAM_ANSI_SETRET(stream, EINVAL, retval, NULL);
#endif /* _UNICODE */
if (retval!=NULL)
{
while (--count)
{
if ((ch = _fgettc_nolock(stream)) == _TEOF)
{
if (pointer == string) {
retval=NULL;
goto done;
}
break;
}
if ((*pointer++ = (_TSCHAR)ch) == _T('\n'))
break;
}
*pointer = _T('\0');
}
/* Common return */
done: ;
}
__finally {
_unlock_str(stream);
}
return(retval);
} 可以看出,它的调用过程中会先调用_lock_str:
[cpp] view plaincopy
#define _lock_str(s) _lock_file(s) _lock_file的内部实现:
[cpp] view plaincopy
void __cdecl _lock_file (
FILE *pf
)
{
/*
* The way the FILE (pointed to by pf) is locked depends on whether
* it is part of _iob[] or not
*/
if ( (pf >= _iob) && (pf <= (&_iob[_IOB_ENTRIES-1])) )
{
/*
* FILE lies in _iob[] so the lock lies in _locktable[].
*/
_lock( _STREAM_LOCKS + (int)(pf - _iob) );
/* We set _IOLOCKED to indicate we locked the stream */
pf->_flag |= _IOLOCKED;
}
else
/*
* Not part of _iob[]. Therefore, *pf is a _FILEX and the
* lock field of the struct is an initialized critical
* section.
*/
EnterCriticalSection( &(((_FILEX *)pf)->lock) );
} 对于_lock函数: [cpp] view plaincopy
void __cdecl _lock (
int locknum
)
{
/*
* Create/open the lock, if necessary
*/
if ( _locktable[locknum].lock == NULL ) {
if ( !_mtinitlocknum(locknum) )
_amsg_exit( _RT_LOCK );
}
/*
* Enter the critical section.
*/
EnterCriticalSection( _locktable[locknum].lock );
}
可以看出,不管加锁的方式如何,它实际上还是会调用系统提供的原始api来进行排他访问,从而避免多线程访问共享资源可能导致读或者写出错的问题。
Q: 那么如何设置将使用单线程版本的c库或者多线程版本的c库? A: 如下图,是vs2010设置使用多线程版本c库的截图:

按照微软的说法,从vs2005开始,单线程版本的C库就已经被移除,所以可以不用担心使用单线程版本C库导致问题了。如果使用的是VC6,依然可以设置使用单线程版本C库。如果使用IDE工具没找到,可以使用命令行工具寻找相关选项:

当然,grep需要cygwin的支持。
2012年08月19日 11点08分
1
Q: C库和系统api之间是什么关系? A: 如下图,简单示意:

可以看出,C库一部分是使用系统api实现自身功能(比如文件操作),另一部分并不会直接依赖系统api,单独实现功能(比如字符串处理)。另外,对于驱动模块,按照不同的理解,也可以放入操作系统内部或者操作系统下层;如果把操作系统看成隐形的CPU和内存的驱动,那么它也可以看成和常规意义的硬件驱动是平级的。而,C库,从理论上来说,没必要和驱动有依赖关系。当然,访问操作系统的方式不仅仅是它提供的api,也是可以通过其它方式来访问。Q:c库和多线程到底什么关系? A: 多线程在操作系统上的运用导致了很多库,包括之前的单线程版本的c库,也必须做出相应修改,才能保证运行不会出现问题。例如,如下是vs2010附带的fgets.c中部分源代码: [cpp] view plaincopy
_TSCHAR * __cdecl _fgetts (
_TSCHAR *string,
int count,
FILE *str
)
{
REG1 FILE *stream;
REG2 _TSCHAR *pointer = string;
_TSCHAR *retval = string;
int ch;
_VALIDATE_RETURN(( string != NULL ) || ( count == 0 ), EINVAL, NULL);
_VALIDATE_RETURN(( count >= 0 ), EINVAL, NULL);
_VALIDATE_RETURN(( str != NULL ), EINVAL, NULL);
if (count == 0)
{
return NULL;
}
/* The C Standard states the input buffer should remain
unchanged if EOF is encountered immediately. Hence we
do not blank out the input buffer here */
/* Init stream pointer */
stream = str;
_lock_str(stream);
__try {
#ifndef _UNICODE
_VALIDATE_STREAM_ANSI_SETRET(stream, EINVAL, retval, NULL);
#endif /* _UNICODE */
if (retval!=NULL)
{
while (--count)
{
if ((ch = _fgettc_nolock(stream)) == _TEOF)
{
if (pointer == string) {
retval=NULL;
goto done;
}
break;
}
if ((*pointer++ = (_TSCHAR)ch) == _T('\n'))
break;
}
*pointer = _T('\0');
}
/* Common return */
done: ;
}
__finally {
_unlock_str(stream);
}
return(retval);
} 可以看出,它的调用过程中会先调用_lock_str:
[cpp] view plaincopy
#define _lock_str(s) _lock_file(s) _lock_file的内部实现:
[cpp] view plaincopy
void __cdecl _lock_file (
FILE *pf
)
{
/*
* The way the FILE (pointed to by pf) is locked depends on whether
* it is part of _iob[] or not
*/
if ( (pf >= _iob) && (pf <= (&_iob[_IOB_ENTRIES-1])) )
{
/*
* FILE lies in _iob[] so the lock lies in _locktable[].
*/
_lock( _STREAM_LOCKS + (int)(pf - _iob) );
/* We set _IOLOCKED to indicate we locked the stream */
pf->_flag |= _IOLOCKED;
}
else
/*
* Not part of _iob[]. Therefore, *pf is a _FILEX and the
* lock field of the struct is an initialized critical
* section.
*/
EnterCriticalSection( &(((_FILEX *)pf)->lock) );
} 对于_lock函数: [cpp] view plaincopy
void __cdecl _lock (
int locknum
)
{
/*
* Create/open the lock, if necessary
*/
if ( _locktable[locknum].lock == NULL ) {
if ( !_mtinitlocknum(locknum) )
_amsg_exit( _RT_LOCK );
}
/*
* Enter the critical section.
*/
EnterCriticalSection( _locktable[locknum].lock );
}
可以看出,不管加锁的方式如何,它实际上还是会调用系统提供的原始api来进行排他访问,从而避免多线程访问共享资源可能导致读或者写出错的问题。
Q: 那么如何设置将使用单线程版本的c库或者多线程版本的c库? A: 如下图,是vs2010设置使用多线程版本c库的截图:

按照微软的说法,从vs2005开始,单线程版本的C库就已经被移除,所以可以不用担心使用单线程版本C库导致问题了。如果使用的是VC6,依然可以设置使用单线程版本C库。如果使用IDE工具没找到,可以使用命令行工具寻找相关选项: 
当然,grep需要cygwin的支持。