【发布时间】:2015-10-23 03:52:35
【问题描述】:
所以,我已经有一段时间没有使用过多的 C 语言了,而且对 malloc 也不是很满意。我不知道这是否是问题的根源,但我遇到了分段错误,如果这里有人看到任何明显可能有问题的东西,它会为我节省很多查找它的麻烦,因为我'甚至不知道从哪里开始。
在启动时提供给 main 的信息:线程限制、帐户限制、输出文件。 可能的输入
TRANS [acct id 1] [amount] [acct id 2] [amount] 等等...
检查 [帐户 ID]
结束
输出不多,大部分信息都提供给输出文件。
如果这段代码特别难以理解或遵循,请告诉我,我会尽力解释。
编辑:所有来自 valgrind 的内存错误都是由调用 strtok() 引起的。我已经搞砸了,但似乎仍然无法解决它。如何从扫描的变量中使用 strtok() 而不会导致这些错误?
appserver.c
-主程序
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include "Bank.c"
#include "appserver.h"
struct account *accounts=NULL;
pthread_t *threads=NULL;
char *threadstatus=NULL;
int done=0;
char busywait=0;
FILE * f;
int main(int argc, char **argv){
int threadcount, banksize;
char* outputpath;
if(argc<4)
{
threadcount=1;
banksize=100;
outputpath="output.txt";
}
else
{
char *tstr=argv[1];
char *sstr=argv[2];
outputpath=argv[3];
threadcount=(int) strtol(tstr, NULL, 10);
banksize=(int) strtol(sstr, NULL, 10);
}
int reqID=0;
struct request *req1, *req2;
req1 = (struct request *) malloc( sizeof(struct request) );
char * in;
char *s;
initialize_status(threadcount);
threads = (pthread_t *) calloc( threadcount, sizeof(pthread_t) );
initialize_accounts(banksize);
initialize_mutex(banksize);
f=fopen(outputpath,"w");
int stringsize=1000;
int threadindex=0;
int i;
while(1)
{
printf("> ");
getline(&in, &stringsize, stdin);
s=strtok(in," ");
if( strcmp( (const char *) s, "CHECK") == 0 )
{
req2 = (struct request *) malloc( sizeof(struct request) );
reqID++;
req1->type = 'b';
s=strtok(NULL," ");
req1->balanceID = (int) strtol( s, NULL, 10);
req1->next = req2;
req1->requestID = reqID;
threadindex=nextthread(threadcount);
if(threadindex<0)
{
busywait=1;
while(busywait==1)
{
//do nothing, waiting for a thread to finish
}
threadindex=nextthread(threadcount);
}
req1->thread=threadindex;
pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
req1=req2;
}
else if( strcmp( (const char *) s, "TRANS") == 0 )
{
req2 = (struct request *) malloc( sizeof(struct request) );
i=0;
reqID++;
req1->type = 't';
while(s!=NULL&&i<10)
{
s = strtok(NULL," ");
req1->transIDs[i] = (int) strtol( s, NULL, 10);
if((s = strtok(NULL," "))==NULL)
{
printf("Bad input: \n");
break;
}
req1->transvals[i] = (int) strtol( s, NULL, 10);
i++;
}
req1->next = req2;
req1->requestID = reqID;
threadindex=nextthread(threadcount);
if(threadindex<0)
{
busywait=1;
while(busywait==1)
{
//do nothing
}
threadindex=nextthread(threadcount);
}
req1->thread=threadindex;
pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
req1=req2;
}
else if( strcmp( (const char *) s, "END") == 0)
{
req1->type = 'e';
threadindex=nextthread(threadcount);
if(threadindex<0)
{
busywait=1;
while(busywait==1)
{
//do nothing
}
threadindex=nextthread(threadcount);
}
req1->thread=threadindex;
pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
for( i = 0; i < threadcount; i++)
pthread_join( threads[i], NULL);
free(accounts);
free(threads);
break;
}
else
{
printf("Try again\n");
}
free(in);
}
return 0;
}
void *workthread(struct request *data)
{
threadstatus[data->thread]='b';
int value;
int i, balance;
printf("< ID %d\n",data->requestID);
while(1)
{
if(data->type == 't')
{
int transamt[10]={0,0,0,0,0,0,0,0,0,0};
int values[10]={0,0,0,0,0,0,0,0,0,0};
for(i=0;i<10;i++)
{
if(!data->transIDs[i])
break;
transamt[i]=data->transvals[i];
value=read_account(data->transIDs[i]);
if((values[i]=value+transamt[i])<0)
{
busywait = 0;
threadstatus[data->thread]='a';
fprintf(f,"%d ISF %d\n",data->requestID,data->transIDs[i]);
return;
}
}
if(translock(data->transIDs) == 1)
{
int ID;
for(i=0;i<10;i++)
{
ID=data->transIDs[i];
accounts[ID-1].value=values[i];
write_account(data->transIDs[i],values[i]);
}
}
transunlock(data->transIDs);
busywait=0;
threadstatus[data->thread]='a';
fprintf(f,"%d OK\n",data->requestID);
return;
}
else if(data->type == 'b')
{
int balance=read_account(data->balanceID);
fprintf(f,"%d BAL %d\n",data->requestID,balance);
threadstatus[data->thread]='a';
busywait=0;
return;
}
else if(data->type == 'e')
{
done=1;
return;
}
}
}
int transunlock(int ids[])
{
struct account *current;
int i=0;
for(i=9;i>=0;i--)
{
current=&accounts[ids[i]-1];
if(ids[i]<1)
continue;
pthread_mutex_unlock(¤t->lock); //unlock previous account
}
return;
}
int translock(int ids[])
{
struct account *current;
int i=0;
for(i=0;i<10;i++)
{
current=&accounts[ids[i]-1];
if(ids[i]<1||pthread_mutex_trylock(¤t->lock)!=0) //if lock attempt fails
{
while(--i>=0)
{
pthread_mutex_unlock(¤t->lock); //unlock previous account
}
return 0;
}
current++;
}
return 1;
}
int initialize_mutex(int n)
{
accounts=(struct account *) malloc(sizeof(struct account) * n);
if(accounts==NULL)
return 0;
int i;
for(i=0;i<n;i++)
{
accounts[i].value=0;
}
return 1;
}
int initialize_status(int n)
{
threadstatus = (char *) malloc( sizeof(char) * n );
int k;
for(k=0;k<n;k++)
{
threadstatus[k]='a';
}
}
int nextthread(int n)
{
int i;
for(i=0;i<n;i++)
{
if(threadstatus[i]=='a')
return i;
}
return -1;
}
appserver.h
#include<pthread.h>
struct account{
pthread_mutex_t lock;
int value;
};
struct request{
char type; //'b' for balance check, 't' for transaction, 'e' for exit
int transIDs[10];
int transvals[10];
int balanceID;
struct request *next;
int requestID;
int thread;
};
void *workthread(struct request *data);
int transunlock(int ids[]);
int translock(int ids[]);
int initialize_mutex(int n);
int initialize_status(int n);
int nextthread(int n);
银行.c
/** Do not modify this file **/
#include "Bank.h"
#include <stdlib.h>
int *BANK_accounts; //Array for storing account values
/*
* Intialize back accounts
* Input: int n - Number of bank accounts
* Return: 1 if succeeded, 0 if error
*/
int initialize_accounts( int n )
{
BANK_accounts = (int *) malloc(sizeof(int) * n);
if(BANK_accounts == NULL) return 0;
int i;
for( i = 0; i < n; i++)
{
BANK_accounts[i] = 0;
}
return 1;
}
/*
* Read a bank account
* Input: int ID - Id of bank account to read
* Return: Value of bank account ID
*/
int read_account( int ID )
{
usleep( 100000 );
return BANK_accounts[ID - 1];
}
/*
* Write value to bank account
* Input: int ID - Id of bank account to write to
* Input: int value - value to write to account
*/
void write_account( int ID, int value)
{
usleep( 100000 );
BANK_accounts[ID - 1] = value;
}
银行.h
/** Do not modify this file **/
/*
* These functions do not provide any error checking.
* If an invalid input is supplied the behavior is
* undefined.
*/
/*
* Intialize n bank accounts with IDs from 1 to n and values of 0.
* Input: int n - Number of bank accounts, must be larger than 0
* Return: 1 if succeeded, 0 if error
*/
int initialize_accounts( int n );
/*
* Read a bank account
* Input: int ID - Id of bank account to read
* Return: Value of bank account ID
*/
int read_account( int ID );
/*
* Write value to bank account
* Input: int ID - Id of bank account to write to
* Input: int value - value to write to account
*/
void write_account( int ID, int value);
就像我之前说的,valgrind 上的所有错误都与 strtok() 调用有关,如下:
条件跳转或移动取决于未初始化的值
使用大小为 8 的未初始化值
大小为 1 的读取无效
进程以信号 11 (SIGSEGV) 的默认操作终止
【问题讨论】:
-
在valgrind 下运行您的代码。这会告诉你你是否在记忆方面做任何可疑的事情。
-
这只是……一个问题。所有忙等待线程微管理的东西。这是自找麻烦:(
-
我应该怎么做呢?如果服务器中的所有线程都在使用,我希望能够以某种方式知道其中一个线程何时完成。我知道我可以加入所有线程,但这只会迫使我等待每个线程完成,有没有办法解决这个问题?
-
我认为你的结构初始化可能有问题。您已经创建了一个排序的链接列表,并且在使用它们之前没有初始化节点。 (指
struct request与成员struct request *next;) -
还值得一提的是,我刚刚对 valgrind 做了一些处理,它返回的几乎每一个错误都与对 strtok() 的调用有关---------- 条件跳转或移动取决于未初始化的值----- 使用大小为 8 的未初始化值----- 大小为 1 的无效读取------ 进程以信号 11 的默认操作终止(SIGSEGV) ------ 所有这些错误都响应输入“TRANS 1 10”。我搞砸了对 strtok 的调用,但没有运气。
标签: c multithreading