Hello, i have created a fairly simple Microblaze-based system, just one core, opb-UART, BRAM, opb-timer and opb-intc. I wrote a small program using the xilkernel-OS which creates two threads printing a thread-specific number and the current clock_ticks. The code is given below. I expect the program to print each second a message of one thread, but that doesn't work. When executing the program both threads seem to enter the code fragment locked by the mutex nearly at the same time as can be seen by the printed clock_ticks. The mutex is declared static and initialized in the static thread created by xilkernel_main and before creating the "Hello world"-threads. <---------------------------> void thread_func(int number) { while (1) { pthread_mutex_lock(&print_mutex); sleep(500); xil_printf("Ticks = %d. Thread %d says: Hello world!\r\n", xget_clock_ticks(), number); sleep(500); pthread_mutex_unlock(&print_mutex); } } <---------------------------> Output via UART: Ticks = 362. Thread 1 says: Hello world! Ticks = 365. Thread 2 says: Hello world! Ticks = 464. Thread 1 says: Hello world! Ticks = 468. Thread 2 says: Hello world! Regards, Andreas
Xilkernel: Problem with mutex
Started by ●September 12, 2006
Reply by ●September 12, 20062006-09-12
Andreas Hofmann schrieb:> Hello, > > i have created a fairly simple Microblaze-based system, just one core, > opb-UART, BRAM, opb-timer and opb-intc. I wrote a small program using > the xilkernel-OS which creates two threads printing a thread-specific > number and the current clock_ticks. The code is given below. I expect > the program to print each second a message of one thread, but that > doesn't work. > > When executing the program both threads seem to enter the code fragment > locked by the mutex nearly at the same time as can be seen by the > printed clock_ticks. > The mutex is declared static and initialized in the static thread > created by xilkernel_main and before creating the "Hello world"-threads. > > <---------------------------> > void thread_func(int number) > { > while (1) > { > pthread_mutex_lock(&print_mutex); > sleep(500); > xil_printf("Ticks = %d. Thread %d says: Hello world!\r\n", > xget_clock_ticks(), number); > sleep(500); > pthread_mutex_unlock(&print_mutex); > } > } > <---------------------------> > > Output via UART: > Ticks = 362. Thread 1 says: Hello world! > Ticks = 365. Thread 2 says: Hello world! > Ticks = 464. Thread 1 says: Hello world! > Ticks = 468. Thread 2 says: Hello world! > > > Regards, > > Andreashm, I think it each thread should print 1 message once a second and that is what you see as well, so everything is working? Antti
Reply by ●September 12, 20062006-09-12
Antti schrieb:> Andreas Hofmann schrieb: > >> Hello, >> >> i have created a fairly simple Microblaze-based system, just one core, >> opb-UART, BRAM, opb-timer and opb-intc. I wrote a small program using >> the xilkernel-OS which creates two threads printing a thread-specific >> number and the current clock_ticks. The code is given below. I expect >> the program to print each second a message of one thread, but that >> doesn't work. >> >> When executing the program both threads seem to enter the code fragment >> locked by the mutex nearly at the same time as can be seen by the >> printed clock_ticks. >> The mutex is declared static and initialized in the static thread >> created by xilkernel_main and before creating the "Hello world"-threads. >> >> <---------------------------> >> void thread_func(int number) >> { >> while (1) >> { >> pthread_mutex_lock(&print_mutex); >> sleep(500); >> xil_printf("Ticks = %d. Thread %d says: Hello world!\r\n", >> xget_clock_ticks(), number); >> sleep(500); >> pthread_mutex_unlock(&print_mutex); >> } >> } >> <---------------------------> >> >> Output via UART: >> Ticks = 362. Thread 1 says: Hello world! >> Ticks = 365. Thread 2 says: Hello world! >> Ticks = 464. Thread 1 says: Hello world! >> Ticks = 468. Thread 2 says: Hello world! >> >> >> Regards, >> >> Andreas > > hm, I think it each thread should print 1 message once a second > and that is what you see as well, so everything is working?No. As the sleeping is done while the mutex is locked each thread should print its message every two seconds. As one tick is approximately 10 ms the message of thread 2 is printed 30 ms after the message of thread 1. So there must be something wrong. Regards, Andreas
Reply by ●September 12, 20062006-09-12
Andreas Hofmann schrieb:> Antti schrieb: > > Andreas Hofmann schrieb: > > > >> Hello, > >> > >> i have created a fairly simple Microblaze-based system, just one core, > >> opb-UART, BRAM, opb-timer and opb-intc. I wrote a small program using > >> the xilkernel-OS which creates two threads printing a thread-specific > >> number and the current clock_ticks. The code is given below. I expect > >> the program to print each second a message of one thread, but that > >> doesn't work. > >> > >> When executing the program both threads seem to enter the code fragment > >> locked by the mutex nearly at the same time as can be seen by the > >> printed clock_ticks. > >> The mutex is declared static and initialized in the static thread > >> created by xilkernel_main and before creating the "Hello world"-threads. > >> > >> <---------------------------> > >> void thread_func(int number) > >> { > >> while (1) > >> { > >> pthread_mutex_lock(&print_mutex); > >> sleep(500); > >> xil_printf("Ticks = %d. Thread %d says: Hello world!\r\n", > >> xget_clock_ticks(), number); > >> sleep(500); > >> pthread_mutex_unlock(&print_mutex); > >> } > >> } > >> <---------------------------> > >> > >> Output via UART: > >> Ticks = 362. Thread 1 says: Hello world! > >> Ticks = 365. Thread 2 says: Hello world! > >> Ticks = 464. Thread 1 says: Hello world! > >> Ticks = 468. Thread 2 says: Hello world! > >> > >> > >> Regards, > >> > >> Andreas > > > > hm, I think it each thread should print 1 message once a second > > and that is what you see as well, so everything is working? > > No. As the sleeping is done while the mutex is locked each thread should > print its message every two seconds. As one tick is approximately 10 ms > the message of thread 2 is printed 30 ms after the message of thread 1. > So there must be something wrong. > > Regards, > Andreasok, if you say so :) for me it wasnt so obvious that obtaining mutex lock on 'print_mutex' will disable all threads from executing! the 30 milliseconds seems to me also correct as this the time it takes to send your hello ... over 9600 baud UART Antti
Reply by ●September 12, 20062006-09-12
Antti schrieb:> Andreas Hofmann schrieb: > >> Antti schrieb: >>> hm, I think it each thread should print 1 message once a second >>> and that is what you see as well, so everything is working? >> No. As the sleeping is done while the mutex is locked each thread should >> print its message every two seconds. As one tick is approximately 10 ms >> the message of thread 2 is printed 30 ms after the message of thread 1. >> So there must be something wrong. >> >> Regards, >> Andreas > > ok, if you say so :) > > for me it wasnt so obvious that obtaining mutex lock on 'print_mutex' > will disable all threads from executing!The other threads should be blocked because sleep() is called while the mutex is held by the sleeping thread. Admittedly my code immediately tries to lock the mutex after releasing it so the other threads may have no chance to execute their lock request. This seems to cause the problems because after enabling yield()-support and calling yield() after pthread_mutex_unlock() solves the problem. The program does now behave as expected. However, i do not fully understand what the kernel is doing when yield() is missing. Shouldn't the other threads, which do not hold the lock, starve while one of the thread locks the mutex over and over again? On the other hand, the Xilinx manual clearly states that when pthread_mutex_unlock() is called "the thread that is at the head of the mutex wait queue is unblocked and allowed to lock the mutex.". Thus calling or omiting yield() shouldn't make any difference. Regards, Andreas
Reply by ●September 12, 20062006-09-12
Andreas Hofmann wrote:> The other threads should be blocked because sleep() is called while the > mutex is held by the sleeping thread. > > Admittedly my code immediately tries to lock the mutex after releasing > it so the other threads may have no chance to execute their lock > request. This seems to cause the problems because after enabling > yield()-support and calling yield() after pthread_mutex_unlock() solves > the problem. The program does now behave as expected. > > However, i do not fully understand what the kernel is doing when yield() > is missing. Shouldn't the other threads, which do not hold the lock, > starve while one of the thread locks the mutex over and over again? > > On the other hand, the Xilinx manual clearly states that when > pthread_mutex_unlock() is called "the thread > that is at the head of the mutex wait queue is unblocked and > allowed to lock the mutex.". Thus calling or omiting yield() shouldn't > make any difference.Andreas, Something is wrong. As your code is written there is no way the 2 threads can print out timestamps so close together. It's as if your pthread locking is having no affect at all. Did you init the mutex? Is the mutex residing on some cacheable memory, and the cache hasn't been flushed? Check the details of the mutex itself, there may be limitations. On blackfin dsp mutex locking was based on their test and set instruction, which was flawed -- you had to use external memory otherwise it didn't work. There may be something similiar going on here. -Dave -- David Ashley http://www.xdr.com/dash Embedded linux, device drivers, system architecture
Reply by ●September 12, 20062006-09-12
Andreas Hofmann wrote:> On the other hand, the Xilinx manual clearly states that when > pthread_mutex_unlock() is called "the thread > that is at the head of the mutex wait queue is unblocked and > allowed to lock the mutex.". Thus calling or omiting yield() shouldn't > make any difference.Unblocking a thread is not the same as giving it processor time. Assuming there are only two threads, then the unblocked thread will not actually execute unless it has a higher priority than the current thread, or the current thread blocks. If the both threads have equal priority, then the blocked thread will also run if the current thread calls sched_yield(). And if the priorities are equal and the current thread uses the SCHED_RR policy, then the blocked thread will also run when the current thread's time quantum expires. If either thread uses the SCHED_OTHER policy then all bets are off. Likewise, if Xilinx's implementation is not POSIX conforming, then who knows what will happen.
Reply by ●September 12, 20062006-09-12
David Ashley wrote:> Did you init the mutex? Is the mutex residing on some cacheable > memory, and the cache hasn't been flushed?On a POSIX-conforming system (ie. compiler + OS + hardware as a whole), the pthread API is sufficient to achieve synchronization. No low level trick are necessary. That's the whole point.
Reply by ●September 12, 20062006-09-12
ryanrsrsrs@yahoo.com wrote:> David Ashley wrote: > >>Did you init the mutex? Is the mutex residing on some cacheable >>memory, and the cache hasn't been flushed? > > > On a POSIX-conforming system (ie. compiler + OS + hardware as a whole), > the pthread API is sufficient to achieve synchronization. No low level > trick are necessary. That's the whole point. >Well something's broken. The code ought to behave differently...At this point there are no options but grasping at straws... The init code wasn't included, you can't just declare a mutex, you need to initialize it: static pthread_mutex_t amutex=PTHREAD_MUTEX_INITIALIZER; For example... -Dave -- David Ashley http://www.xdr.com/dash Embedded linux, device drivers, system architecture
Reply by ●September 12, 20062006-09-12
David Ashley wrote:> Well something's broken. The code ought to behave > differently...At this point there are no options but > grasping at straws...Check the behavior of sleep(). I take it sleep(500) is not meant to sleep for 500 seconds. POSIX sleep() has wierd interactions with setitimer(), ualarm(), usleep(), and SIGALRM. It can also return early due to signal delivery. Nanosleep() is easier to use. Try the following: lock print "begin thread %i" sleep print "end thread %i" unlock