2个线程,1个打印字母A-Z,另一个打印1-26 要求交替打印 A1B2C3...Z26

代码结构:

pthread线程同步 pthread_cond_wait, pthread_cond_signal_#include

* main.c

//
// 2个线程,1个打印字母A-Z,另一个打印1-26 要求交替打印 A1B2C3...Z26
//
#include <stdio.h>
#include <pthread.h>

#ifndef NULL
#define NULL (void *)0
#endif

#ifndef bool
typedef int bool;
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif

typedef void *(*start_routine_t)(void *);

pthread_mutex_t print_mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t print_cv = PTHREAD_COND_INITIALIZER;
volatile bool should_alpha = true;  /* should print alphabets? */

void *print_alphabets(void *param) {
    int n = 26;
    int c = 0x41;

    while (n-- > 0) {
        pthread_mutex_lock(&print_mtx);
        while (!should_alpha) {
            pthread_cond_wait(&print_cv, &print_mtx);
        }
        fputc(c++, stdout);
        should_alpha = false;
        pthread_mutex_unlock(&print_mtx);
        pthread_cond_signal(&print_cv);
    }
    return NULL;
}

void *print_digits(void *param) {
    int c;
    for (c = 1; c < 27; c++) {
        pthread_mutex_lock(&print_mtx);
        while (should_alpha) {
            pthread_cond_wait(&print_cv, &print_mtx);
        }
        fprintf(stdout, "%d", c);
        should_alpha = true;
        pthread_mutex_unlock(&print_mtx);
        pthread_cond_signal(&print_cv);
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t t1, t2;

    pthread_create(&t1, NULL, print_alphabets, NULL);
    pthread_create(&t2, NULL, print_digits, NULL);
    pthread_join(t1, 0);
    pthread_join(t2, 0);
    fputc(0x0a, stdout);

    return 0;
}

* CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(thread_sync)

set(CMAKE_C_STANDARD 99)

link_libraries("pthread")

add_executable(thread_sync main.c)

Build:


====================[ Build | thread_sync | Debug ]============================= C:\Windows\system32\wsl.exe --distribution Ubuntu --exec /bin/bash -c "export CLION_IDE=TRUE && export CLICOLOR_FORCE=1 && export TERM=xterm && export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' && export JETBRAINS_IDE=TRUE && cd /mnt/e/CLionProjects/thread_sync/cmake-build-debug && /usr/bin/cmake --build /mnt/e/CLionProjects/thread_sync/cmake-build-debug --target thread_sync -- -j 6" [100%] Built target thread_sync Build finished


Run:

C:\Windows\system32\wsl.exe --distribution Ubuntu --exec /bin/bash -c "cd /mnt/e/CLionProjects/thread_sync/cmake-build-debug && /mnt/e/CLionProjects/thread_sync/cmake-build-debug/thread_sync"
A1B2C3D4E5F6G7H8I9J10K11L12M13N14O15P16Q17R18S19T20U21V22W23X24Y25Z26

Process finished with exit code 0

用全局变量global不好,在实际项目中容易出错。改成参数传给线程routine

//
// 2个线程,1个打印字母A-Z,另一个打印1-26 要求交替打印 A1B2C3...Z26
//
#include <stdio.h>
#include <pthread.h>

typedef struct {
    pthread_mutex_t mtx;
    pthread_cond_t cv;
    volatile int alpha;
} print_t;

void *print_alphabets(void *param) {
    int n = 26;
    int c = 0x41;
    print_t *p = (print_t *)param;

    while (n-- > 0) {
        pthread_mutex_lock(&p->mtx);
        while (!p->alpha) {
            pthread_cond_wait(&p->cv, &p->mtx);
        }
        fputc(c++, stdout);
        p->alpha = 0;
        pthread_mutex_unlock(&p->mtx);
        pthread_cond_signal(&p->cv);
    }
    return NULL;
}

void *print_digits(void *param) {
    int c;
    print_t *p = (print_t *)param;

    for (c = 1; c < 27; c++) {
        pthread_mutex_lock(&p->mtx);
        while (p->alpha) {
            pthread_cond_wait(&p->cv, &p->mtx);
        }
        fprintf(stdout, "%d", c);
        p->alpha = 1;
        pthread_mutex_unlock(&p->mtx);
        pthread_cond_signal(&p->cv);
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t t1, t2;
    print_t p = {
        .mtx = PTHREAD_MUTEX_INITIALIZER,
        .cv = PTHREAD_COND_INITIALIZER,
        .alpha = 1  /* should print alphabets? */
    };
    pthread_create(&t1, NULL, print_alphabets, &p);
    pthread_create(&t2, NULL, print_digits, &p);
    pthread_join(t1, 0);
    pthread_join(t2, 0);
    fputc(0x0a, stdout);

    return 0;
}

注意, mutex, cond必须要初始化,否则阻塞不动。

pthread线程同步 pthread_cond_wait, pthread_cond_signal_线程同步_02

 

pthread线程同步 pthread_cond_wait, pthread_cond_signal_thread_03

pthread线程同步 pthread_cond_wait, pthread_cond_signal_thread_04

mutex的lock, unlock范围尽可能小。先unlock再signal或者broadcast

多线程代码里不能用sleep,因为不知道要等几秒。什么时候该等待、什么时候该继续往下走。

sleep可以被signal打断

void bcl_udelay( long usec) {
    struct timeval timeout;
    
    timeout.tv_usec = usec % 1000000;
    timeout.tv_sec = usec / 1000000;

    select(1, NULL, NULL, NULL, &timeout);
}

可以用select系统调用实现一个

/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

#include <sys/select.h>

int pselect(int nfds, fd_set *readfds, fd_set *writefds,
            fd_set *exceptfds, const struct timespec *timeout,
            const sigset_t *sigmask);