3 Replies - 2114 Views - Last Post: 18 June 2008 - 03:13 PM Rate Topic: -----

#1 Beca  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 05-June 08

pthread ...some questions

Posted 17 June 2008 - 01:29 PM

Something is wrong the threads sometimes work and sometimes they do whatever they want… please help me!

Here some explanations:

I want to move 6 counters at the same time by using threads. In order to do it I need to use and share the no volatile SRAM and a Bus of communication of a board. So I have two principal functions:

1. This function “Full_Init_Counter” initializes the counters, they always must be checking if there is a new increment so their threads never end. At the moment I’m testing only with two counters.

void Full_Init_Counter(void)
{
	// where  ID_Table is a global variable.
	pthread_create(&ID_Table[0], NULL, Func_InitCounter0, NULL);
	pthread_create(&ID_Table[1], NULL, Func_InitCounter1, NULL);
}
 


1.1. The function “Func_InitCounter0” and “Func_InitCounter1”: They manage the counter 1 and 2 respectively. They access a specific memory address (SRAM) where it reads the increment and moves the counters but at the same time could be another thread writing a new increment.

Questions:
1. This is a theory question. Can I use the same local variables for different functions to be executed by new threads? For example in the “Func_InitCounter1” can I use the same local variables of “Func_InitCounter0”? Actually I haven’t done it but I like to do it because I’m going to have 6 similar functions.


void* Func_InitCounter0(void* param) 
{
	// local variables
	long unsigned int C0_DATA1, C0_DATA2;
	int Result_Read0, Result_Write0, Result_Read1, Result_Write1;

	while(1) // The thread always must be checking the new increment any time.
	{
		// Leer el contenido en la sram
		Result_Read0=sram_read32(3150, &C0_DATA1);
		if(Result_Read0 == -1)
		{
			printf("Error.\n");
		}
		else
		{
			if((C0_DATA1 > 0)&&(C0_DATA1 != 0)) // Move the counter0
			{
				/***************************************/
				Here I read the BUS and move the counter 0 once, I use
				Two Sleep(20) and a pthread_mutex_lock/unlock to 
				Protect the access to the BUS but the problem is that 
				 The six threads need to use the BUS.
				/***************************************/
				// Decrementar el valor
				C0_DATA1=C0_DATA1-1;
				// Guardar el nuevo valor en la SRAM
				Result_Write0=sram_write32(3150, C0_DATA1);
				if(Result_Write0==-1)
				{
					printf("Error. \n");
				}
			}
		
			if(C0_DATA1 == 0) //  Get or wait the new increment
			{
				// Protegiendo la escritura en la posición 3154
				pthread_mutex_lock(&mutex0);
					Result_Read1=sram_read32(3154,&C0_DATA2);
					if(Result_Read1 == -1)
					{
						printf("Error. \n");
					}
																	if(C0_DATA2==0)
					{
						pthread_cond_wait(&cond0, &mutex0);
						sram_read32(3154,&C0_DATA2);
					}
					C0_DATA1 = C0_DATA2;
					C0_DATA2 = 0;
					Result_Write1=sram_write32(3154,C0_DATA2);
					sram_write32(3150, C0_DATA1);
					if(Result_Write1==-1)
					{
						printf("Error \n");
					}
				pthread_mutex_unlock(&mutex0);
			}
						
			if(C0_DATA1 < 0)
			{
				printf("Error C0_DATA1 negativo. \n");
			}

		}
	}
	return(NULL);
} 






2. The another function is “add(unsigned int counterNumber, unsigned int amount)” This



void add(unsigned int counterNumber, unsigned int amount)
{
	switch(counterNumber)
	{
		case 1:																   pthread_create(&ID_InTable[0],NULL,Func_Main0,(void*)&amount);
			break;

		case 2:			pthread_create(&ID_InTable[1],NULL,Func_Main1,(void*)&amount);
			break;

		case 3:						pthread_create(&ID_InTable[2],NULL,Func_Main2,(void*)&amount);
			break;

		case 4:			pthread_create(&ID_InTable[3],NULL,Func_Main3,(void*)&amount);
			break;

		case 5:			pthread_create(&ID_InTable[4],NULL,Func_Main4,(void*)&amount);
			break;

		case 6:			pthread_create(&ID_InTable[5],NULL,Func_Main5,(void*)&amount);
			break;

		default:
			break;

	}
}




3. De description of the Func_Main0 is below, I used the “pthread_detach(pthread_self())” because I want to free some resources of the system.
• Questions:
2. If the function “Func_Main0” is used several times so the mutex0
makes a queue. Is it possible that the function
“pthread_detach(pthread_self())” eliminate something and finally
I lost any Data?

3. What exactly eliminates “pthread_detach(pthread_self)”? local
variables? mutex0?

void* Func_Main0(void* param)
{
	long unsigned int C0_DAT2;
	int Res0_Read, Res0_Write;
	
	pthread_mutex_lock(&mutex0);

		dato0 = *((long unsigned int*)param); 
		Res0_Read = sram_read32(3154,&C0_DAT2);

		if(Res0_Read==-1)
		{
			printf("Error. \n");		
		}
		C0_DAT2 = C0_DAT2 + dato0;								Res0_Write = sram_write32(3154, C0_DAT2);
		if(Res0_Write)
		{
			printf("Error. \n");
		}
		pthread_cond_signal(&cond0);
	
	pthread_mutex_unlock(&mutex0);
	
	pthread_detach(pthread_self());

	return(NULL);
}



4. Finally in the main function :


void main()
{	
	int i;

	// Put Zero in the following memory addresses  3150, 3154, 3158, 3162
	sram_write32(3150,0);
	sram_write32(3154,0);
	sram_write32(3158,0);
	sram_write32(3162,0);

	if(Full_Init_Counter())
	{
		printf("Error creando los hilos. \n");
	}

	// Test the counter increment
	add(1,100);
	add(2,200);
	
	
	//Sleep(100);
	
	for(i=0; i< 10; i++)
	{
		add(1,2);
	}
	
	while(1)
	{}
}




The bigger Problem:

If I write Sleep(100) it works okay, but I don’t want to use it because the increment could happen any time, so when I don’t use the Sleep could happen many estrange thinks for example:
• Only the increment of the “FOR” happens, it means that the counter1 increment 10 positions.
• Another estrange think is that the counter 2 get 2 as increment instead of 100;

Could be the problem the variable “the function add”, but How can I improve this problem???

Thank you for your time, I hope someone can help me.

Kind Regards

Beca

Is This A Good Question/Topic? 0
  • +

Replies To: pthread ...some questions

#2 perfectly.insane  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 70
  • View blog
  • Posts: 644
  • Joined: 22-March 08

Re: pthread ...some questions

Posted 17 June 2008 - 04:26 PM

Beca said:

The bigger Problem:

If I write Sleep(100) it works okay, but I don’t want to use it because the increment could happen any time, so when I don’t use the Sleep could happen many estrange thinks for example:
• Only the increment of the “FOR” happens, it means that the counter1 increment 10 positions.
• Another estrange think is that the counter 2 get 2 as increment instead of 100;


In multi-threaded applications, you shouldn't use timing to synchronize threads. I'm guessing that Func_Main0..6 do their thing and then exit? Perhaps you should wait for them to terminate if this is the case. You can again use pthread_join (which waits until a specified thread terminates) to wait for these threads to complete, or use another synchronization primitive (such as a mutex). You can start multiple threads at a time, but you should wait for both of them to terminate, or one of them if that's all your concerned with being in sync.

Looking at what you've written, it only looks like the first one is significant. However, a bus is not an inherently capable of multi-tasking, so everything will be sequential anyway. A message-passing model might make more sense (I don't know what you're trying to do though). Essentially, that would involve one thread in the background, that takes items off of a queue, and interprets them as commands. So, the add function would, instead of starting a thread, would push an "instruction" to a queue, and the other thread would pop it off and execute it. Of course, this queue would have to be protected by a mutex, but all commands would be guaranteed to be sequential without having to fuss with much synchronization.

Of course, if you want to read a counter, there would be another command for that, but that command would have a result. There are multiple ways of doing this, but if there is only one receiver, you could use either another queue or a shared variable protected by another mutex to have the background thread send feedback back to the requesting thread.

Quote

1. This is a theory question. Can I use the same local variables for different functions to be executed by new threads? For example in the “Func_InitCounter1” can I use the same local variables of “Func_InitCounter0”? Actually I haven’t done it but I like to do it because I’m going to have 6 similar functions.


The same variable names? Yes... Each thread has it's own stack, so it wouldn't matter if they had the same names, or if you had more than one thread calling the same function. But no, you should not use pointers pointing to a local variable from one thread in another, unless you can guarantee that the function that has the variable that is being pointed to will not exit before it is done being used.

Quote

2. The another function is “add(unsigned int counterNumber, unsigned int amount)” This


There is a problem with this function. You can't give a pointer to the calling thread and expect it to be valid if that pointer points to a stack variable (in this case, an argument of add. Instead, you could just cast the integer itself directly to a void* (essentially, putting the integer as the pointer value), and then converting it back on the other end. It's obviously not actually a pointer to good memory in this case, but it should serve the purpose provided that both sides interpret it correctly.

Quote

. If the function “Func_Main0” is used several times so the mutex0
makes a queue. Is it possible that the function
“pthread_detach(pthread_self())” eliminate something and finally
I lost any Data?


You can call a mutex recursively, but you have to give it a special attribute. It should be in the documentation for pthread_mutex_init.

pthread_detach has no effect on threads that are running.

You can make a thread detach itself automatically when it exits. There is an attribute for this as well... see the docs on pthread_create.

Calling pthread_join on a thread waiting for it to complete will do the same thing, so pthread_detach often is unnecessary.

Quote

3. What exactly eliminates “pthread_detach(pthread_self)”? local
variables? mutex0?


No... local variables themselves are always free once a function exits. I'm thinking TLS (thread-local storage) related items (see pthread_key_create) and possibly some internal accounting by the thread, if needed.
Was This Post Helpful? 0
  • +
  • -

#3 Beca  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 05-June 08

Re: pthread ...some questions

Posted 17 June 2008 - 08:03 PM

Thanks a lot perfectly.insame... I'm analysing your suggestions.

The first thing that I did after read your post was, change the function add, please I want to be sure if I get your idea

void add(unsigned int counterNumber, void*amount)
{
switch(counterNumber)
	{
		case 1:																	 
			pthread_create(&ID_InTable[0],NULL,Func_Main0,amount);
			break;

		case 2:			
			pthread_create(&ID_InTable[1],NULL,Func_Main1,amount);
			break;

		case 3:						
		   pthread_create(&ID_InTable[2],NULL,Func_Main2,amount);
			break;

		case 4:			
			pthread_create(&ID_InTable[3],NULL,Func_Main3,&amount);
			break;

		case 5:			
			pthread_create(&ID_InTable[4],NULL,Func_Main4,amount);
			break;

		case 6:			
		pthread_create(&ID_InTable[5],NULL,Func_Main5,amount);
			break;

		default:
			break;

	}
}




and in the main function, I have to do:

void main()
{
int data0, data1, data2;
data0=100;
data1=210;
data2=20;
// Put Zero in the following memory addresses  3150, 3154, 3158, 3162
	sram_write32(3150,0);
	sram_write32(3154,0);
	sram_write32(3158,0);
	sram_write32(3162,0);

	if(Full_Init_Counter())
	{
		printf("Error creando los hilos. \n");
	}
	add(1,&data0);
	add(2,&data1);

	for(i=0; i<20; i++)
{
add(1,&data2);
}
	 while(1)
{}

}



Now it works without problems, but imaging that someone is using at any time the function add, how can it put the data into?

please tell me if that was the idea, I'm going to try the another possibility with queues later
Was This Post Helpful? 0
  • +
  • -

#4 perfectly.insane  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 70
  • View blog
  • Posts: 644
  • Joined: 22-March 08

Re: pthread ...some questions

Posted 18 June 2008 - 03:13 PM

Nope... not quite. This is what I mean:

void add(unsigned int counterNumber, unsigned int amount)
{
switch(counterNumber)
	{
		case 1:																	 
						// This uses the value of amount as the actual pointer value.  Note that there is no ampersand.
			pthread_create(&ID_InTable[0],NULL,Func_Main0, (void*)amount);
			break;

		case 2:			
			pthread_create(&ID_InTable[1],NULL,Func_Main1, (void*)amount);
			break;
				.
				.
		}
}

void Func_Main0(void* data)
{
	  // Since data isn't a valid address, we won't dereference it, but simply assign it's value to a local variable.
	  // In effect, this gives a simple pass-by-value.
	  unsigned int data0 = (unsigned int)data;
	  .
	  .
	  .
}





Again, the problem is the lifetime of the variables. If you pass a pointer to a thread function, you must guarantee that it's valid throughout the life of the thread, which means making it a global variable, or waiting for the thread to return. So, actually, what you wrote will also work properly in this instance, because you have a while(1) loop, but if the function did not have such, one would need to use a global, or use pthread_join to wait for the threads to terminate., i.e.

add(1, &value);
add(2, &value2);
pthread_join(ID_InTable[0]);
pthread_join(ID_InTable[1]);

What I wrote above hackishly does away with the problem by not passing by reference at all, but by value (coerced into pretending to be a pointer when it's not).
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1