信号安全函数
进程捕获到信号并对其进行处理时,进程正在执行的正常指令序列就被信号处理程序临时中断,它首先执行该信号处理程序中的指令。如果从信号处理程序中返回,则继续执行在捕获到信号时进程正在执行的正常的指令序列。有如下三类函数不能在信号处理程序中调用(非信号安全函数)
a)已知它们使用静态数据结构(如getpwnam函数)
b)它们调用malloc或free函数
c)标准I/O函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构。这里需要特别说明一点,书上或网上一些例子,信号处理函数中调用了printf,这里仅仅为了直观说明程序的运行,printf不能在信号处理函数中调用。
度量C程序执行时间
项目里有一些调试日志,统计执行数据库插入等耗时操作的时间用于提升性能。统计时间程序真可谓是五花八门。我个人认为比较好的写法就是如下这种形式(跨平台):
clock_t begin = clock();
/* here, do your time-consuming job */
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
pthread_cond_timedwait使用误区
上周定位一个同事转手过来的异常问题,说程序无法正常工作,非常奇怪。由于没有现场环境,只能去review代码,发现这个模块居然将gettimeofday和pthread_cond_timewait一起使用。gettimeofday的一般用法如下:
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("USAGE: %s loop-iterations\n", argv[0]);
return 1;
}
int iterations = atoi(argv[1]);
struct timeval start, end;
gettimeofday(&start, NULL);
for (int i = 0; i < iterations; i++)
{
}
gettimeofday(&end, NULL);
printf("%ld\n", ((end.tv_sec * 1000000 + end.tv_usec)
- (start.tv_sec * 1000000 + start.tv_usec)));
return 0;
}
gettimeofday与pthread_cond_timewait一起使用的方式:
void mywait(int timeInMs)
{
struct timespec timeToWait;
struct timeval now;
int rt;
gettimeofday(&now,NULL);
timeToWait.tv_sec = now.tv_sec+5;
timeToWait.tv_nsec = (now.tv_usec+1000UL*timeInMs)*1000UL;
pthread_mutex_lock(&fakeMutex);
rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
pthread_mutex_unlock(&fakeMutex);
printf("\nDone\n");
}
但是上面这种写法存在一个问题:如果修改了系统时间会导致等待时间异常,正确的方法是使用相对时间,一个可以运行的例子如下:
// gcc -o pwait pwait.cpp -lpthread
#include <stdio.h>
#include <pthread.h>
#include <time.h>
typedef struct mutex_cond
{
pthread_condattr_t cattr;
pthread_mutex_t i_mutex;
pthread_cond_t i_cv;
void* i_sigevent;
}mutex_cond_t;
int main()
{
mutex_cond_t mcond;
int ret = pthread_condattr_init(&(mcond.cattr));
if (ret != 0)
{
return (1);
}
mcond.i_sigevent = NULL;
ret = pthread_mutex_init ( &(mcond.i_mutex), NULL);
ret = pthread_condattr_setclock(&(mcond.cattr), CLOCK_MONOTONIC);
ret = pthread_cond_init(&(mcond.i_cv), &(mcond.cattr));
struct timespec tv;
while(1)
{
clock_gettime(CLOCK_MONOTONIC, &tv);
printf("%lld\n", (long long) tv.tv_sec);
tv.tv_sec += 20;// 设置20秒后没收到事件超时返回
ret = pthread_cond_timedwait(&(mcond.i_cv), &(mcond.i_mutex), &tv);
}
return 0;
}
这里函数pthread_condattr_setclock通过CLOCK_MONOTONIC设置成相对时间,不会依赖系统时间的变化,clock_gettime这里获取到的时间应该是系统启动时间,可以通过uptime验证。
[root c++]#./a.out
6700
[root c++]#uptime
00:24:52 up 1:51, 1 user, load average: 0.01, 0.02, 0.00
fopen函数
在项目代码里看到如下类似代码:
if ( access(filename, F_OK) != 0 )
{
int fd = open(filename, O_CREAT|O_RDWR, 0666);
if ( fd == -1 )
{
//error handle
return -1;
}
close(fd);
(void)chmod(filename, 0666);
}
这种写法存在问题,多个进程同时执行到access,如果文件不存在都会走到下面的逻辑,无法做到原子操作,APUE第三章里介绍了一种判断文件是否存在的原子操作:fopen中添加O_EXCL。
其实上面的代码可以改写成:
int fd = open(filename, O_CREAT|O_RDWR|O_EXCL, 0666);
//错误码不是文件不存在,错误处理
if (EEXIST != errno && fd == -1 )
{
//error handle
return -1;
}
close(fd);
(void)chmod(filename, 0666);
文件系统只读
开发虚拟机输入cp pc之后,记不住名字使用tab看下有哪些pc开头的文件,结果提示如下错误:
cp pc-bash: cannot create temp file for here-document: Read-only file system
使用mount看了下
/dev/sda1 on / type ext4 (ro,relatime,errors=remount-ro,data=ordered)
这里尝试使用:
mount -o remount,rw /dev/sdb1
仍然提示文件系统只读,使用fsck /dev/sda1可以修复磁盘
[root ~]#fsck /dev/sda1
fsck from util-linux 2.31.1
e2fsck 1.44.1 (24-Mar-2018)
/dev/sda1 contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Deleted inode 3538955 has zero dtime. Fix<y>? yes
Inodes that were part of a corrupted orphan linked list found. Fix<y>? yes
Inode 3538963 was part of the orphaned inode list. FIXED.
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Free blocks count wrong (12502342, counted=12538642).
Fix<y>? yes
Inode bitmap differences: -3538955 -3538963
Fix<y>? yes
Free inodes count wrong for group #432 (5813, counted=5815).
Fix<y>? yes
Free inodes count wrong (3746983, counted=3747057).
Fix<y>? yes
/dev/sda1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sda1: ***** REBOOT SYSTEM *****
/dev/sda1: 447247/4194304 files (0.1% non-contiguous), 4238062/16776704 blocks
reboot后接着重新以读写方式挂载磁盘/dev/sda1即可修复该问题。