Ubuntu LED控制台出现类Matrix乱码,如何排查线程信号量代码错误?
Hey there, let's dig into those weird random characters popping up in your Ubuntu console—plus fix the thread and semaphore issues you're running into. This glitch is almost certainly tied to memory corruption or unsafe thread behavior, so let's break it down step by step.
1. Critical Array Out-of-Bounds Error (Likely the Root Cause)
First up, a big red flag in your main function:
for (i = 0; i < 3; i += 1) { rc = pthread_create(&thread[i], NULL, led_toggle_thr, (void *)i); assert(rc == 0); }
You're creating 3 LED toggle threads, but your global arrays flashing and flashing_delay only have 2 elements (indices 0 and 1). The third thread will use id = 2, which means it's accessing flashing[2] and flashing_delay[2]—this is a classic array out-of-bounds access.
Memory corruption from out-of-bounds reads/writes is almost certainly causing those "Matrix-style" random characters in your console. Fix this by only creating 2 LED threads (one for each LED):
// Create threads for LED 0 and 1 only for (i = 0; i < 2; i += 1) { rc = pthread_create(&thread[i], NULL, led_toggle_thr, (void *)i); assert(rc == 0); }
2. Thread Handle Overwrite
Right after creating the 3 LED threads, you overwrite thread[2] with the keyboard thread:
rc = pthread_create(&thread[2], NULL, keyboard_thr, NULL); assert(rc == 0);
This loses track of the third LED thread's handle, leading to resource leaks and undefined behavior. With the fix above (only 2 LED threads), thread[2] is free for the keyboard thread, so this becomes safe.
3. Unlocked Access to Shared Variables
Your flashing array is a shared variable (likely modified by keyboard_thr to toggle LED states). In led_toggle_thr, you read flashing[id] outside the semaphore critical section:
if (flashing[id]) { sem_wait(&mutex); led_toggle((leds_t)id); sem_post(&mutex); }
This creates a race condition: the value of flashing[id] could change between the if check and the led_toggle call. Wrap the entire check and action in the semaphore lock to ensure consistency:
sem_wait(&mutex); if (flashing[id]) { led_toggle((leds_t)id); } sem_post(&mutex);
4. High-Frequency Console Updates Causing Glitches
Your led_info_thr runs in an infinite loop with no delay, spamming lcd_write_at as fast as possible. This floods the console with updates, compounding memory corruption issues and causing display artifacts. Add a small delay to throttle updates:
void *led_info_thr(void *arg) { char flashing_str[2]={'N','N'}; while(true) { sem_wait(&mutex); // Lock once for all shared reads/writes for(int i = 0; i < 2; i++) { flashing_str[i] = flashing[i] ? 'Y' : 'N'; lcd_write_at(i, 0, "LED%d F:%c D:%d", i, flashing_str[i], flashing_delay[i]); } sem_post(&mutex); usleep(100000); // 100ms delay to reduce update frequency } return NULL; }
I also moved the semaphore lock outside the loop—no need to lock/unlock twice per iteration; locking once is more efficient and safer.
5. Thread Argument Type Safety
When passing i as a thread argument, you cast it to void* then back to unsigned long. On 64-bit systems, this can cause issues since int and void* might be different sizes. A safer approach (optional but good practice):
// In main for (i = 0; i < 2; i += 1) { unsigned long *id = malloc(sizeof(unsigned long)); *id = i; rc = pthread_create(&thread[i], NULL, led_toggle_thr, id); assert(rc == 0); } // In led_toggle_thr void *led_toggle_thr(void *arg) { unsigned long id = *(unsigned long*)arg; free(arg); // Don't forget to free the allocated memory! while (true) { // ... rest of your code ... } }
Final Quick Checks
- Make sure
sem_init(&mutex, 0, 1);is correctly written (your code had&mutexwhich is an HTML escape—use&mutexin your actual code). - Ensure all shared variables (
flashing,flashing_delay) are only accessed within semaphore-locked critical sections in every thread that uses them (includingkeyboard_thr).
These fixes should eliminate the memory corruption causing the Matrix glitches and resolve your thread/semaphore issues.
内容的提问来源于stack exchange,提问作者Nick

