I'm working on a C project using Pthread that needs to share some variables. There are several lines of code written yet and I just realized that using shared global variables doesn't work quite well because of the cache system.
I find on stackoverflow that a solution is to pass the adress of the variable (in my case it's more than one) to the thread function, what does it change?
Since my thread functions call other functions who will modify the globals, it's a bit painful to add a parameter to the chain of called functions where one function modify the globals.
So I was wondering, would it work to declare global pointers for each globals and use them to acess the global instead of the real globals?
I think it's a superficial inderiction but why wouldn't it work after all?
My program is an UDP network protocol whre networks look like rings or circled simple linked list. Instances of the program on the network are called entities.
An entity entity can insert on a ring or ask an entity to create another ring (dupplication), so the other entity would be on two ring.
The interface is sort of a shell where commands can leads to sending messages on the ring. Messages circle all over the rings after being stopped when they have ever been seen.
The shell is in the main thread, there is a thread for message treatment, another to manage insertion, and there is also a thread to detect broken rings. The problems is located in the ring tester thread. The thread initialize a global array (volatile short ring_check[NRING]) of size of the maximum ring numbers for an entity, initialize the first element with 0 according to the actual number of rings and the rest with -1, after that it send a test message in each ring and sleeps during a timeout of 30sec. When the timeout has finished, it checks for the values in the array.
The values are changed by the thread for message treatment, when a test message went went back, it detects it by its content and write -1 to the appropriate ring_check element.
The problem is that after a dupplication, the two rings are tested but the checking for the second failed (ring_check[1] == 0) and I really don't know why... The test message is received, immediately after the sending, after the message treatment modifies ring_check[1] to 0 I print it to see if the change is really made and it prints 1. But about 20 to 30sec later, the ring_tester wake up from his sleeping time and it reads 0 in ring_check[1].
short volatile ring_check[NRING+1];
// The function in the ring tester thread
static void test_ring() {
// initialize ring_check array
debug("ring_tester", GREEN "setting ring_check to -1...");
char port_diff[5];
// send test messages in each rings
int fixed_nring = getnring();
for (int i = fixed_nring+1; i < NRING; ++i) {
ring_check[i] = -1;
}
for (int i = 0; i < fixed_nring + 1; i++) {
debug("ring_tester", GREEN "setting ring_check %d to 0...", i);
ring_check[i] = 0;
itoa4(port_diff, ent.mdiff_port[i]);
debug("ring_tester", GREEN "sending test to ring %d...", i);
sendmessage(i, "TEST", "%s %s", ent.mdiff_ip[i], port_diff);
}
debug("test_ring", GREEN "timeout beginning...");
sleep(timeout);
debug("test_ring", GREEN "end of timeout.");
for (int i = 0; i < fixed_nring + 1 && ring_check[i] != -1; i++) {
debug("test_ring", GREEN "ring_check[%d]:%d", i, ring_check[i]);
if (ring_check[i]) {
debug("test_ring", GREEN "ring %d: checked.", i);
continue;
}
else {
debug("test_ring", GREEN "ring %d: checking failed. Ring broken...", i);
continue;
}
}
// The function called by the message treatment thread
static int action_test(char *message, char *content, int lookup_flag) {
debug("action_test", RED "entering function...");
if (content[15] != ' ' || content[20] != 0) {
debug("action_test", RED "content not following the protocol."\
"content: \"%s\"", content);
return 1;
}
if (lookup_flag) {
char mdiff_port[5];
int fixed_nring = getnring();
for (int i = 0; i < fixed_nring + 1 && ring_check[i] != -1; ++i) {
itoa4(mdiff_port, ent.mdiff_port[i]);
// find ring associated with message and actualize the checking
if (strncmp(content, ent.mdiff_ip[i], 15) == 0 &&
strncmp(&content[16], mdiff_port, 4) == 0 &&
ring_check[i] != -1) {
ring_check[i] = 1;
debug("action_test",
RED "correspondance found, ring_check[%d]:%d", i, ring_check[i]);
return 0;
}
}
}
else {
sendpacket_all(message);
}
return 0;
}
You could define a global structure such as thread_inputparam. Put all the global variables' addresses in it and send to all threads, the adress of this structure variable.
int global1;
struct thread_input {
int *g1;
// add other globals'addresses
}thread_inputparam;
thread_inputparam.g1=&global1;
I'm attempting to fully justify (left and right columns line-up) input from files and this is what I came up with. The input files have embedded commands so from my pseudo output below I start justifying at the company's line and end at telephone As you can see it randomly joins two of the lines read together. Can someone please tell me why it's doing this? My input files definitely have newline characters in them since I double checked they were entered.
Also how do I do the following: Check if my read line will fit into my output array (of 40 char)? If it doesn't I want to move the overflowed string(s) into the next line or char(s) if it's easier. This one isn't as necessary as my first question but I would really like to make the output as nice as possible and I don't know how to restrict and carry overflow from read lines into the next output array.
Since it began to escape from AT&T's Bell Laboratories in
the early 1970's, the success of the UNIX
operating system has led to many different
versions: recipients of the (at that time free) UNIX system
code all began developing their own different
versions in their own different ways for use and sale.
Universities, research
institutes, government bodies and computer
companies all began using the powerful
UNIX system to develop many of the
technologies which today are part of a
UNIX system. Computer aided design,
manufacturing control systems,laboratorysimulations,even the Internet itself,
all began life with and because of UNIX
Today, without UNIX systems, the Internewould come to a screeching halt.
Most telephone calls could not be made,
electronic commerce would grind to a halt and
there would have never been "Jurassic Park"!
Below is my justify function that's passed the read file line using fgets in another function. The printf lines are just for debugging.
void justify(char strin[]){
int i = 0; //strin iterator
int j = 0; //out iterator
int endSpaces = LINE + 1 - strlen(strin);
int voids = countwords(strin) - 1;
printf("Voids: %d\n", voids);
printf("Input: %s", strin);
//No words in line, exit
if (voids <= 0)
return;
//How many to add between words
int addEvenly = endSpaces/voids;
int addUnevenly = endSpaces % voids;
printf("space to distribute: %d evenly: %d unevenly: %d\n", endSpaces, addEvenly, addUnevenly);
//Copy space left of array to output
while (strin[i] == ' '){
outLine[j++] = ' ';
i++;
}
//One word at a time
while (endSpaces > 0 || addUnevenly > 0){
//Copy letters into out
while (strin[i] != ' '){
outLine[j] = strin[i];
i++;
j++;
}
//Add the necessary spaces between words
if (addEvenly > 0){
for (int k = 0; k < addEvenly; k++){
outLine[j++] = ' ';
}
}
//Distribute to the left
if (addUnevenly > 0){
outLine[j++] = ' ';
endSpaces--;
addUnevenly--;
}
printf("Output: %s\n\n", outLine);
endSpaces = endSpaces - addEvenly;
//Finish copying rest of input to output when no more spaces to add
if (endSpaces == 0 && addUnevenly == 0){
while (strin[i] != '\0')
outLine[j++] = strin[i++];
printf("Output 2: %s\n", outLine);
}
}
fprintf(out, "%s", outLine);
}
On sunday I created a function (justifyline()) able to justify and indent a line you give it as input. It outputs a buffer containing the justified (formatted) text and any eventual text-remainder; such a remainder may be used as input to the function justifyline().
After this step I've used the file below (text.txt) to test the behaviour of such a function. That test demonstrates me the need to use also word wrapping between lines. Then I've written the function formatLineByLine(). The function formatLineByLine() doesn't care of void lines.
Text file (text.txt): (I used the text in your question trying to correct it, but not all I've corrected, then the input file suffers of this fact!)
Since it began to escape from AT&T's
Bell Laboratories in the early 1970's,
the success of the UNIX operating system
has led to many different versions:
recipients of the (at that time free)
UNIX system code all began developing
their own different versions in their
own different ways for use and sale.
Universities, research institutes,
government bodies and computer companies
all began using the powerful UNIX system
to develop many of the technologies which
today are part of a UNIX system.
Computer aided design, manufacturing
control systems, laboratory simulations,
even the Internet itself, all began life
with and because of UNIX Today, without
UNIX systems, the Internet would come to a
screeching halt. Most telephone calls
could not be made, electronic commerce
would grind to a halt and there would
have never been "Jurassic Park"!
The output of the function formatLineByLine()
ABCDE12345678901234567890123456789012345
Since it began to escape from
AT&T's Bell Laboratories in the
early 1970's, the success of the
UNIX operating system has led to
many different versions: recipients
of the (at that time free) UNIX
system code all began developing
their own different versions in
their own different ways for use
and sale. Universities, research
institutes, government bodies and
computer companies all began using
the powerful UNIX system to develop
many of the technologies which
today are part of a UNIX system.
Computer aided design,
manufacturing control systems,
laboratory simulations, even the
Internet itself, all began life
with and because of UNIX Today,
without UNIX systems, the Internet
would come to a screeching halt.
Most telephone calls could not be
made, electronic commerce would
grind to a halt and there would
have never been "Jurassic Park"!
Another step is the idea to use a paragraph per paragraph justifycation. Then I've written the function justifyParagraph(). The function formatInParagraphs() reads the file text.txt and prints it justified using the function justifyParagraph().
The output of the function formatInParagraphs()
ABCDE12345678901234567890123456789012345
Since it began to escape from
AT&T's Bell Laboratories in the
early 1970's, the success of the
UNIX operating system has led to
many different versions: recipients
of the (at that time free) UNIX
system code all began developing
their own different versions in
their own different ways for use
and sale.
Universities, research
institutes, government bodies and
computer companies all began using
the powerful UNIX system to develop
many of the technologies which
today are part of a UNIX system.
Computer aided design,
manufacturing control systems,
laboratory simulations, even the
Internet itself, all began life
with and because of UNIX Today,
without UNIX systems, the Internet
would come to a screeching halt.
Most telephone calls could not be
made, electronic commerce would
grind to a halt and there would
have never been "Jurassic Park"!
The function justifyline() is able to create a justified buffer with indentation (parameter size_t indent) and to use also a single space between the words (parameter int nospacing sent as 1).
The function justifyParagraph() is able to create a justified buffer with line indentation (parameter: size_t indent) and 1st line indentation (parameter: size_t indentstart). The formatted output may be directly printed when a NULL output buffer is sent to the function (parameter char **outbuf sent as NULL). The last line the function generates may be justified or not (parameter: int notFrmtLast sent as 1).
Both justification functions, when the parameter char **outbuf points a NULL pointer ( *outbuf == NULL ), allocate memory using malloc() . In this case you have to free the buffer after its use. If this parameter is passed as NULL to the function justifyParagraph(), the function prints the elaborated output, if outbuf is passed as NULL to the function justifyline(), the function returns an error.
The code is below. An issue of this code is that, in some cases, the length of the string should be computed using a function different from strlen(). To avoid this problem you may use these functions with lines that have a single space between the words. Such a problem affects the functions justifyParagraph() and formatLineByLine().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int justifyLine(char *inbuf, char **outbuf, size_t linelen, char ** endptr, size_t indent, int nospacing);
int justifyParagraph(char *inbuf,char **outbuf,size_t linelen,size_t indentstart,size_t indent,int notFmtLast);
int formatLineByLine(FILE *f, size_t linelen,size_t indent, int notFrmtLast);
int formatInParagraphs(FILE *f, size_t linelen,size_t indentstart,size_t indent, int notFrmtLast);
int justifyParagraph(char *inbuf,char **outbuf,size_t linelen,size_t indentstart,size_t indent,int notFmtLast)
{
char *optr=NULL,*endp=NULL;
size_t len,s;
int retval,nf;
for(;;) { //Error control loop
if (inbuf==NULL) {
retval=0x10;break;
}
if (indent+indentstart>linelen) {
retval=0x20;break;
}
if (outbuf!=NULL) {
if (*outbuf==NULL) {
if ( (*outbuf=malloc(linelen+1))==NULL ){
retval=0x30;break;
}
}
optr=*outbuf;
}
endp=inbuf;
indent+=indentstart;
len=linelen-indent;
s=indentstart;nf=0;
while( *endp!=0) {
if (notFmtLast && strlen(endp)<linelen-indent)
nf=1;
if ( (retval=justifyLine(endp,&optr,linelen,&endp,
indent,nf)) ) {
retval|=0x40;break;
}
if (outbuf!=NULL) {
optr+=strlen(optr);
*optr++='\n';
*optr=0;
} else {
puts(optr);
}
indent-=s;
len+=s;
s=0;
}
break; //Close error ctrl loop!
}
if (outbuf==NULL && optr!=NULL)
free(optr);
return retval;
}
int justifyLine(char *inbuf,char **outbuf,size_t linelen, char ** endptr,size_t indent,int nospacing)
{
size_t textlen,tmp;
size_t spctoadd,spcodd,spcin;
size_t timetoodd;
size_t ibidx,obidx,k,wc;
char * endp;
char * outb=NULL;
int retval=0;
for(;;) { //Error control loop
endp=inbuf;
if (inbuf==NULL) {
retval=1;break;
}
if (indent>linelen) {
retval=2;break;
}
if (outbuf==NULL) {
retval=3;break;
}
if (*outbuf==NULL) {
if ( (*outbuf=malloc(linelen+1))==NULL ){
retval=4;break;
}
}
outb=*outbuf;
//Leave right spaces
while(*inbuf==' ')
inbuf++;
if (*inbuf==0) {
endp=inbuf;
*outb=0;
break; //exit from error loop without error!
}
linelen-=indent;
//Count words and the minimum number of characters
ibidx=0;
wc=0;textlen=0;k=1;endp=NULL;
while ( *(inbuf+ibidx)!=0 ) {
if (*(inbuf+ibidx)==' ') {
ibidx++;continue;
}
//There's a char!
k=ibidx; //last word start
tmp=textlen;
wc++;textlen++; //add the space after the words
//textlen<linelen because textlen contains also the space after the word
// while(textlen<=linelen && *(inbuf+ibidx)!=' ' && *(inbuf+ibidx) ) {
while(*(inbuf+ibidx)!=' ' && *(inbuf+ibidx) ) {
textlen++;ibidx++;
}
if (textlen>linelen+1) {
endp=inbuf+k;
textlen=tmp;
wc--;
break;
}
}
textlen=textlen-wc;
if (endp==NULL) {
endp=inbuf+ibidx;
}
if (textlen<2) {
*outb=0;
break; //exit from error loop without error!
}
//Prepare outbuf
memset(outb,' ',linelen+indent);
*(outb+linelen+indent)=0;
ibidx=0;
obidx=indent;
if (wc>1) {
if (!nospacing) {
//The odds are max in number == wc-2
spctoadd=linelen-textlen;
} else {
spctoadd=wc-1;
}
spcin=spctoadd/(wc-1);
spcodd=spctoadd % (wc-1);
if (spcodd)
timetoodd=(wc-1)/spcodd;
k=timetoodd;
while(spctoadd) {
while(*(inbuf+ibidx)!=' ') {
*(outb+obidx++)=*(inbuf+ibidx++);
}
obidx+=spcin;spctoadd-=spcin;
if (spcodd && !(--k)) {
k=timetoodd;
spcodd--;
spctoadd--;
obidx++;
}
while(*(inbuf+ ++ibidx)==' ');
}
}
while(*(outb+obidx) && *(inbuf+ibidx) && *(inbuf+ibidx)!=' ')
*(outb+obidx++)=*(inbuf+ibidx++);
//There're words longer then the line!!!
if (*(inbuf+ibidx) && *(inbuf+ibidx)!=' ')
endp=inbuf+ibidx;
break; //Terminate error ctrl loop.
}
if (endptr!=NULL)
*endptr=endp;
return retval;
}
int formatLineByLine(FILE *f, size_t linelen,size_t indent, int notFrmtLast)
{
char text[250],*app;
//justifyLine allocates memory for the line if the outbuf (optr) value is NULL
char * optr=NULL;
size_t j,k;
//print a ruler
for(j=0;j<indent;j++)
printf("%c",'A'+(char)j);
for(j=1;j<=linelen-indent;j++)
printf("%c",'0'+(char)(j%10));
printf("\n");
//starts printing
fseek(f,0,SEEK_SET);
j=0;
while(fgets(text+j,sizeof(text)-j,f)) {
if ( (app=strrchr(text+j,'\n')) ) {
*app=0;
}
k=strlen(text);
if (strlen(text)<linelen-indent) {
if (!*(text+k) && *(text+k-1)!=' ') {
*(text+k++)=' ';
*(text+k)=0;
}
j=k;
continue;
}
app=text;
do {
//justifyLine allocates memory for the line if the outbuf (optr) value is NULL
if ( justifyLine(app,&optr,linelen,&app,indent,0) ) {
if (optr!=NULL)
free(optr);
return 1;
}
printf("%s\n",optr);
j=(*app!=0)?strlen(app):0;
} while(j>linelen-indent);
if (j) {
strcpy(text,app);
*(text+j++)=' ';
*(text+j)=0;
}
}
if (*text!=0 && j) {
if ( justifyLine(text,&optr,linelen,NULL,indent,notFrmtLast) )
{
if (optr!=NULL)
free(optr);
return 2;
}
printf("%s\n",optr);
}
//justifyLine allocates memory for the line if the outbuf value is NULL
if (optr!=NULL)
free(optr);
return 0;
}
int formatInParagraphs(FILE *f, size_t linelen,size_t indentstart,size_t indent, int notFrmtLast)
{
char text[1024], *app;
//To uncomment when you use the commented justifyParagraph line.
//see below
//char *outbuf=NULL;
size_t j;
//print a ruler
for(j=0;j<indent;j++)
printf("%c",'A'+(char)j);
for(j=1;j<=linelen-indent;j++)
printf("%c",'0'+(char)(j%10));
printf("\n");
//starts printing
fseek(f,0,SEEK_SET);
j=0;
while(fgets(text+j,sizeof(text),f)) {
if ( (app=strrchr(text+j,'\n')) ) {
*app++=' ';*app=0;
}
if ( *(text+j)==' ' && !*(text+j+1) ) {
//The following commented line allocates memory creating a paragraph buffer!
//doesn't print the formatted line.
//justifyParagraph(text,&outbuf,linelen,indentstart,indent,notFrmtLast);
//This line directly print the buffer allocating and de-allocating
//only a line buffer. It prints the formatted line.
justifyParagraph(text,NULL,linelen,indentstart,indent,notFrmtLast);
j=0;
//To uncomment when you use the commented justifyParagraph line.
// printf("%s\n\n",outbuf);
puts("");
} else {
j+=strlen(text+j);
}
}
return 0;
}
int main(void)
{
FILE * file;
file=fopen("text.txt","r");
formatLineByLine(file,40,5,1);
puts("");
formatInParagraphs(file,40,5,5,1);
fclose(file);
return 0;
}
You were incredibly close – but you forgot one thing!
After copying a word into outLine, you insert the correct number of additional spaces, and continue with 'the next word'. However, at that point the input pointer i still is at the end of the previously copied word (so it points to the first space immediately after that). The test while (strin[i] != ' ') then immediately fails and you insert the additional spaces at that point again. This continues until you run out of spaces to add, and at the very end you add what was not processed, which is "the entire rest of the string".
The fix is simple: after copying your word into outLine, copy the original space(s) as well, so the i iterator gets updated to point to the next word.
//One word at a time
while (endSpaces > 0 || addUnevenly > 0)
{
//Copy letters into out
while (strin[i] != ' ')
{
outLine[j] = strin[i];
i++;
j++;
}
//Copy original spaces into out <-- FIX!
while (strin[i] == ' ')
{
outLine[j] = strin[i];
i++;
j++;
}
With this, your code works entirely as you intended. Output:
|Since it began to escape from AT&T's Bell Laboratories in|
|the early 1970's, the success of the UNIX|
|operating system has led to many different|
|versions: recipients of the (at that time free) UNIX system|
|code all began developing their own different|
|versions in their own different ways for use and sale.|
| Universities, research|
|institutes, government bodies and computer|
|companies all began using the powerful |
|UNIX system to develop many of the |
|technologies which today are part of a |
|UNIX system. Computer aided design, |
|manufacturing control systems,laboratorysimulations,even the Internet itself, |
|all began life with and because of UNIX |
|Today, without UNIX systems, the Internewould come to a screeching halt.|
|Most telephone calls could not be made,|
|electronic commerce would grind to a halt and|
|there would have never been "Jurassic Park"! |
Possible improvements
Justified lines should never begin with whitespace (your Copy space left of array to output part). Just increment the pointer there:
//Copy space left of array to output
while (strin[i] == ' ')
{
// outLine[j++] = ' ';
i++;
endSpaces++;
}
(and move the calculation for How many to add between words below this, because it changes endSpaces).
The same goes for spaces at the end. You can adjust endSpaces at the start
int l = strlen(strin);
while (l > 0 && strin[l-1] == ' ')
{
l--;
endSpaces++;
}
and suppress copying the trailing spaces into outLn at the bottom. (That needs some additional tinkering, I couldn't get it right first time.)
It is much neater to ignore multiple spaces inside the input string as well, but that takes a bit more code.
With these three implemented, you get a slightly neater output:
|Since it began to escape from AT&T's Bell Laboratories in|
|the early 1970's, the success of the UNIX|
|operating system has led to many different|
|versions: recipients of the (at that time free) UNIX system|
|code all began developing their own different|
|versions in their own different ways for use and sale.|
|Universities, research|
|institutes, government bodies and computer|
|companies all began using the powerful|
|UNIX system to develop many of the|
|technologies which today are part of a|
|UNIX system. Computer aided design,|
|manufacturing control systems,laboratorysimulations,even the Internet itself,|
|all began life with and because of UNIX|
|Today, without UNIX systems, the Internewould come to a screeching halt.|
|Most telephone calls could not be made,|
|electronic commerce would grind to a halt and|
|there would have never been "Jurassic Park"!|
A drawback of this one-line-at-a-time method is that it cannot easily be rewritten to gather input until a line overflows. To do so, you need:
a routine that skips all spaces and return a pointer to the next word.
a routine that reads words until a line is 'overfull' – that is, the number of words plus (the number of words - 1) for spaces is larger than your LINE value. This uses routine #1 and outputs exactly one justified line.
You need to pass on the location and number of strings from your main to both these routines, and in both check if you are at the end of either a single input line or the entire input array.
I've written this main that contains two simple methods to center a text in a line. The first method only prints the text variable without modifying it, the second method modifies the text variable and then prints it. (Here method is not intended as function, the code contains two examples which you may translate easily in simple functions)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char text[81],fmt[10];
int linelen=80,tlen;
int spacetocenter=0;
printf("Insert text to center [max %lu char]:\n",sizeof(text)-1);
if (scanf("%[^\n]",text)<1) {
perror("scanf");
return -1;
}
getchar(); //Leaves return from the buffer
tlen=strlen(text);
spacetocenter=(linelen-tlen)/2;
if (spacetocenter<0)
spacetocenter=0;
//Method one (this doesn't modify text)
//This method directly prints the contents of text centered.
//----------------------------------------------------------
snprintf(fmt,sizeof(fmt),"%%%+ds\n",spacetocenter+tlen);
//printf("%s\n",fmt); // prints the used format
printf(fmt,text);
//Method two (this modifies text)
//This method modifies the contents of the variable text
//----------------------------------------------------------
memmove(text+spacetocenter,text,tlen+1);
memset(text,' ',spacetocenter);
printf("%s\n",text);
return 0;
}
Note:
After the second method is applied tlen no longer contains the length of text!
The program consider the line of 80 chars, if you need shorter/longer lines you have to modify the value of the variable linelen.