- 论坛徽章:
- 0
|
本帖最后由 wp00000008 于 2010-03-09 09:12 编辑
先介绍一下系统
Linux tech.tianya.cn 2.6.18-8.el5 #1 SMP Thu Mar 15 19:57:35 EDT 2007 i686 i686 i386 GNU/Linux
cc (GCC) 4.1.1 20070105 (Red Hat 4.1.1-52)
关于malloc的线程安全性,主流说法是线程安全的。这个说法很容易让人引起共鸣:如果malloc不是线程安全的,那多线程编程不是太可怕了吗?
我相信malloc是线程安全的,结果这回出事了。
[root@tech iotest]# ./a.out /root/chengsj/disk0 50 256
dir=/root/chengsj/disk0, threads=50, cache=256k
段错误 (core dumped)
core dump的那一行是一个free
由此引起对c标准库的严重怀疑。c标准库中,没有什么东西是线程安全的,兄弟们悠着点,谨防黑手。
以下是代码。这个代码是用于多线程环境下IO读取性能测试,利用不同的线程数量和cache大小进行比较,以期得到比较好的优化结果。
由于是测试代码,就没有很注意细节。
现有代码在运行时会有core dump,但是对malloc加锁之后(程序中被注释的部分),就不会core dump了
/*
* iotest.c
*
* Created on: 2010-3-8
* Author: cheng
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
#include "iothreads.h"
int main(int argc, char *argv[])
{
if (argc != 4) {
printf("Usage: iotest src-dir threadnum cache-k \n");
return 1;
}
char *dir;
char buf[1024];
int threads, cachelen, result;
DIR *fdir;
struct dirent * pdir;
time_t t1, t2;
double total;
dir = argv[1];
threads = atoi(argv[2]);
cachelen = atoi(argv[3]);
printf("dir=%s, threads=%d, cache=%dk\n", dir, threads, cachelen);
if (threads_init() != 0) {
printf("error threads_init. \n");
return 1;
}
fdir = opendir(dir);
if (fdir == NULL) {
printf("error open dir %s: %s\n", dir, strerror(errno));
return 1;
}
while((pdir = readdir(fdir))!=NULL) {
if (pdir->d_type == 8) {
threads_add(dir, pdir->d_name);
}
}
closedir(fdir);
t1 = time(NULL);
threads_create(threads, cachelen);
while (threads_count()) {
sleep(1);
}
t2 = time(NULL);
total = threads_total();
printf("time(s): %d, ", t2-t1);
printf("bytes(M): %f, rate(M/s):%f \n", total, total/(t2-t1));
return 0;
}
/*
* iothreads.h
*
* Created on: 2010-3-8
* Author: cheng
*/
#ifndef IOTHREADS_H_
#define IOTHREADS_H_
#define MAX_FILE_COUNT 10*1024
#define MAX_FILE_LEN 1024
int init_pthread_lock(pthread_mutex_t *pthread_lock);
double threads_total();
int threads_init();
int threads_add(char *path, char *name);
int threads_create(int num, int cache);
int threads_count();
#endif /* IOTHREADS_H_ */
/*
* iothreads.c
*
* Created on: 2010-3-8
* Author: cheng
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <netinet/tcp.h>
#include <sys/sendfile.h>
#include "iothreads.h"
static char st_files[MAX_FILE_COUNT][MAX_FILE_LEN];
static pthread_mutex_t st_lock;
static int st_count;
static int st_idx;
static int st_cache;
volatile static int st_threads;
volatile static double st_total;
int init_pthread_lock(pthread_mutex_t *pthread_lock)
{
pthread_mutexattr_t mat;
int result;
if ((result=pthread_mutexattr_init(&mat)) != 0)
{
return result;
}
if ((result=pthread_mutexattr_settype(&mat, \
PTHREAD_MUTEX_ERRORCHECK_NP)) != 0)
{
return result;
}
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0)
{
return result;
}
if ((result=pthread_mutexattr_destroy(&mat)) != 0)
{
return result;
}
return 0;
}
double threads_total()
{
return st_total;
}
int total_add(int len)
{
int result;
if ((result=pthread_mutex_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error pthread_mutex_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
return (result);
}
st_total = st_total+len*1.0/(1024*1024);
pthread_mutex_unlock(&st_lock);
return 0;
}
int threads_init()
{
int result;
st_count = 0;
st_idx = -1;
st_threads = 0;
st_total = 0;
if ((result=init_pthread_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error init_pthread_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
return (result);
}
return 0;
}
int threads_add(char *path, char *name)
{
int result;
if ((result=pthread_mutex_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error pthread_mutex_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
return (result);
}
if (st_count < MAX_FILE_COUNT-1) {
st_count ++;
sprintf(st_files[st_count-1], "%s/%s\0", path, name);
} else {
fprintf(stderr, "\t Error threads_add[%d / %s]: %d exceed. \n", __LINE__, __FILE__, MAX_FILE_COUNT);
}
pthread_mutex_unlock(&st_lock);
return 0;
}
void* threads_run(void *p)
{
char file[MAX_FILE_LEN];
char *buf;
int result, filefd, len;
/*
if ((result=pthread_mutex_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error pthread_mutex_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
st_threads --;
return;
}
*/
buf = (char *)malloc(st_cache*1024);
//pthread_mutex_unlock(&st_lock);
if (buf != NULL) {
while (1) {
if ((result=pthread_mutex_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error pthread_mutex_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
continue;
}
st_idx ++;
if (st_idx >= st_count) {
pthread_mutex_unlock(&st_lock);
break;
}
memset(file, 0, sizeof(file));
memcpy(file, st_files[st_idx], MAX_FILE_LEN);
pthread_mutex_unlock(&st_lock);
filefd = open(file, O_RDONLY);
if (filefd < 0) {
fprintf(stderr, "Error[%d / %s]: %s while open [%s].\n", __LINE__, __FILE__, strerror(errno), file);
continue;
}
while ((len=read(filefd, buf, st_cache*1024)) > 0) {
total_add(len);
}
close(filefd);
}
free(buf);
buf = NULL;
} else fprintf(stderr, "Error[%d / %s]: %s while malloc.\n", __LINE__, __FILE__, strerror(errno));
st_threads --;
}
int threads_create(int num, int cache)
{
int result, i;
pthread_t tid;
if ((result=pthread_mutex_lock(&st_lock)) != 0) {
fprintf(stderr, "\t Error pthread_mutex_lock[%d / %s]: %s \n", __LINE__, __FILE__, strerror(result));
return (result);
}
for (i=0; i<num; i++) {
if ((result=pthread_create(&tid, NULL, threads_run, NULL)) != 0) {
fprintf(stderr, "threads_create:pthread_create error: %s\n", strerror(result));
return (result);
}
}
st_threads = num;
st_cache = cache;
pthread_mutex_unlock(&st_lock);
return 0;
}
int threads_count()
{
return st_threads;
} |
|