• linux c 线程相关函数


    线程相关函数(1)-pthread_create(), pthread_join(), pthread_exit(), pthread_cancel() 创建取消线程 

    一. pthread_create()

    #include <pthread.h>

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

    pthread_t *thread:           传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID)
    const pthread_attr_t *attr:      
    线程属性设置,如使用默认属性,则传NULL
    void *(*start_routine) (void *):      
    函数指针,指向新线程应该加载执行的函数模块
    void *arg:            
    指定线程将要加载调用的那个函数的参数

    返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。

    二.pthread_join()

    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);


    pthread_t thread:        回收线程的tid
    void **retval:          接收退出线程传递出的返回值
    返回值:成功返回0,失败返回错误号

    注意:

    调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

    如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
    如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
    如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。

    如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

    三.pthread_exit()

    该函数可以用于在线程退出时传递线程的返回值。

    #include <pthread.h>
    void pthread_exit(void *retval);
    void *retval:      线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。

    注意和exit函数的区别,任何线程里exit导致进程退出,其他线程未工作结束,主线程退出时不能return或exit。需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

    四.pthread_cancel()

    #include <pthread.h>
    int pthread_cancel(pthread_t thread);

    定义在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。可以在头文件pthread.h中找到它的定义:

    #define PTHREAD_CANCELED ((void *) -1)

    五.示例

    复制代码
    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    
    
    void *thr_fn1(void *arg)
    {
        printf("thread 1 returning\n");
        return (void*)1;
    }
    
    
    void *thr_fn2(void *arg)
    {
        printf("thread 2 exiting\n");
        pthread_exit((void*)2);
    }
    
    
    void *thr_fn3(void *arg)
    {
        while(1) {
            printf("thread 3 writing\n");
            sleep(1);
        }
    }
    
    
    int main()
    {
        pthread_t tid;
        void *retval;
    
        pthread_create(&tid, NULL, thr_fn1, NULL);
        pthread_join(tid, &retval);
        printf("thread 1 exit code %d\n", (int)retval);    
        
        pthread_create(&tid, NULL, thr_fn2, NULL);
        pthread_join(tid, &retval);
        printf("thread 2 exit code %d\n", (int)retval);
    
        pthread_create(&tid, NULL, thr_fn3, NULL);
        sleep(3);
        // 调用pthread_cancel函数取消第三个线程
        pthread_cancel(tid);
        // 如果线程是通过pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED
        pthread_join(tid, &retval);
        printf("thread 3 exit code %d\n", (int)retval);
        
        return 0;
    }
    复制代码

    运行结果:

    thread 1 returning
    thread 1 exit code 1
    thread 2 exiting
    thread 2 exit code 2
    thread 3 writing
    thread 3 writing
    thread 3 writing
    thread 3 exit code -1

    线程相关函数(2)-pthread_self()获取调用线程ID

     

    获取调用线程tid

    #include <pthread.h>
    pthread_t pthread_self(void);

    示例:

    复制代码
    #include <pthread.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    
    void *printids(void *arg)
    {
        const char *str = (const char *)arg;
    
        pid_t pid;
        pthread_t tid;
        
        pid = getpid();
        tid = pthread_self();
        printf("%s pid %u tid %u (0x%x)\n", str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
        
    }
    
    
    
    
    int main()
    {    
    
        pthread_t tid;
        int err;    
    
        err = pthread_create(&tid, NULL, printids, "new thread: ");
        if (err != 0) {
            fprintf(stderr, "can't create thread: %s\n", strerror(err));
            exit(1);
        }    
        printids("main thread: ");    
        sleep(1);
        return 0;
    
    }
    复制代码

    运行结果:

    main thread: pid 4959 tid 9791296 (0x956740)
    new thread: pid 4959 tid 1480448 (0x169700)

    线程相关函数(3)-pthread_detach()将某个线程设成分离态

     

    #include <pthread.h>
    int pthread_detach(pthread_t tid);


    pthread_t tid:  分离线程的tid
    返回值:成功返回0,失败返回错误号。

    一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
    通常情况下,若创建一个线程不关心它的返回值,也不想使用pthread_join来回收(调用pthread_join的进程会阻塞),就可以使用pthread_detach,将该线程的状态设置为分离态,使线程结束后,立即被系统回收。

    示例代码:

    复制代码
    #include <pthread.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    void *thr_fn(void *arg)
    {
        int n = 10;
        while(n--) {
            printf("thread count %d\n", n);
            sleep(1);
        }
        return (void *)1;
    }
    
    
    int main()
    {    
        
        pthread_t tid;
        void *retval;
        int err;
    
        pthread_create(&tid, NULL, thr_fn, NULL);
        pthread_detach(tid);
            
        while(1) {
            err = pthread_join(tid, &retval);
            if (err != 0)
                fprintf(stderr, "thread %s\n", strerror(err));
            else 
                fprintf(stderr, "thread exit code %d\n", (int)retval);
            sleep(1);
        }
        return 0;
    }
    复制代码

    运行结果:

    thread Invalid argument
    thread count 9
    thread Invalid argument
    thread count 8
    thread Invalid argument
    thread count 7
    thread Invalid argument
    thread count 6
    thread Invalid argument
    thread count 5
    thread Invalid argument
    thread count 4
    thread Invalid argument
    thread count 3
    thread Invalid argument
    thread count 2
    thread Invalid argument
    thread count 1
    thread Invalid argument
    thread count 0
    thread Invalid argument
    thread Invalid argument

    线程相关函数(4)-pthread_mutex_lock(), pthread_mutex_unlock() 互斥锁

     

    互斥锁实例:

    #include <pthread.h>
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    int pthread_mutex_unlock(pthread_mutex_t *mutex);

    示例代码:

    复制代码
    #include <pthread.h>
    #include <stdio.h>
    
    #define NLOOP 5000
    
    static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
    static int counter;
    
    void *doit(void *);
    
    
    int main()
    {
        pthread_t tidA, tidB;
        pthread_create(&tidA, NULL, doit, NULL);
        pthread_create(&tidB, NULL, doit, NULL);
    
        /*wait for both threads to terminate*/
        pthread_join(tidA, NULL);
        pthread_join(tidB, NULL);
        
        return 0;
    }
    
    
    void *doit(void *arg)
    {    
        int i, val;
        for (i=0; i<NLOOP; i++) {
            pthread_mutex_lock(&counter_mutex);
            val = counter;
            printf("%x: %d\n", (unsigned int)pthread_self(), val+1);
            counter = val + 1;
            pthread_mutex_unlock(&counter_mutex);
        }
        return NULL;
    }
    复制代码

    运行结果:

    ....

    71025700: 9979
    71025700: 9980
    71025700: 9981
    71025700: 9982
    71025700: 9983
    71025700: 9984
    71025700: 9985
    71025700: 9986
    71025700: 9987
    71025700: 9988
    71025700: 9989
    71025700: 9990
    71025700: 9991
    71025700: 9992
    71025700: 9993
    71025700: 9994
    71025700: 9995
    71025700: 9996
    71025700: 9997
    71025700: 9998
    71025700: 9999
    71025700: 10000

    线程相关函数(5)-pthread_rwlock_rdlock(),pthread_rwlock_wrlock() 读写锁

     

    读共享,写独占

    pthread_rwlock_t
    pthread_rwlock_init
    pthread_rwlock_destroy
    pthread_rwlock_rdlock
    pthread_rwlock_wrlock
    pthread_rwlock_tryrdlock
    pthread_rwlock_trywrlock
    pthread_rwlock_unlock

    示例代码:

    复制代码
    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    
    static int counter;
    static pthread_rwlock_t rwlock;
    
    void *th_write(void *arg)
    {
        int t, i;
        for (i=0; i<5; i++) {
            pthread_rwlock_wrlock(&rwlock);
            t = counter;
            usleep(100);
            printf("Write Thread(%x) counter=%d, ++counter=%d\n", (int)pthread_self(), t, ++counter);
            pthread_rwlock_unlock(&rwlock);
            usleep(100);
        }
    
    }
    
    
    void *th_read(void *arg)
    {
        while(1) {
            pthread_rwlock_rdlock(&rwlock);
            printf("Read Thread(%x) counter=%d\n", (int)pthread_self(), counter);
            pthread_rwlock_unlock(&rwlock);
            usleep(100);
        }
    }
    
    
    int main()
    {
        int i;
        pthread_t tid[8];    
    
        pthread_rwlock_init(&rwlock, NULL);
        for (i=0; i<3; i++)
            pthread_create(&tid[i], NULL, th_write, NULL);
        for (i=0; i<5; i++)
            pthread_create(&tid[i+3], NULL, th_read, NULL);
        for (i=0; i<8; i++)
            pthread_join(tid[i], NULL);
    
        pthread_rwlock_destroy(&rwlock);    
        return 0;
    }
    复制代码

    运行结果:

    Read Thread(f901e700) counter=0
    Read Thread(f981f700) counter=0
    Read Thread(f881d700) counter=0
    Read Thread(fa020700) counter=0
    Read Thread(fa821700) counter=0
    Write Thread(fb022700) counter=0, ++counter=1
    Write Thread(fb823700) counter=1, ++counter=2
    Write Thread(fc024700) counter=2, ++counter=3
    Write Thread(fb022700) counter=3, ++counter=4
    Write Thread(fb823700) counter=4, ++counter=5
    Write Thread(fc024700) counter=5, ++counter=6
    Write Thread(fb022700) counter=6, ++counter=7
    Write Thread(fb823700) counter=7, ++counter=8
    Write Thread(fc024700) counter=8, ++counter=9
    Write Thread(fb022700) counter=9, ++counter=10
    Write Thread(fb823700) counter=10, ++counter=11
    Write Thread(fc024700) counter=11, ++counter=12
    Write Thread(fb022700) counter=12, ++counter=13
    Write Thread(fb823700) counter=13, ++counter=14
    Write Thread(fc024700) counter=14, ++counter=15
    Read Thread(f901e700) counter=15
    Read Thread(f981f700) counter=15
    Read Thread(f881d700) counter=15
    Read Thread(fa020700) counter=15
    Read Thread(fa821700) counter=15
    Read Thread(f901e700) counter=15
    Read Thread(f981f700) counter=15
    Read Thread(f881d700) counter=15
    Read Thread(fa020700) counter=15

    ...

    线程相关函数(6)-pthread_cond_wait(),pthread_cond_signal(), 条件变量

     

    pthread_cond_t
    pthread_cond_init
    pthread_cond_destroy
    pthread_cond_wait
    pthread_cond_timedwait
    pthread_cond_signal
    pthread_cond_broadcast

    生产者消费者模型:

    复制代码
    #include <pthread.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <time.h>
    
    struct msg {
        struct msg *next;
        int num;
    };
    
    
    struct msg *head;
    pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    
    
    void *consumer(void *p)
    {
        struct msg *mp;
        for(;;) {
            pthread_mutex_lock(&lock);
            while (head == NULL)
                pthread_cond_wait(&has_product, &lock);
            mp = head;
            head = mp->next;
            pthread_mutex_unlock(&lock);
            printf("Consume %d\n", mp->num);
            free(mp);
            sleep(rand() % 5);    
        }
    }
    
    void *producer(void *p)
    {
        struct msg *mp;
        for(;;) {
            mp = malloc(sizeof(struct msg));
            mp->num = rand() % 1000 + 1;
            printf("Produce %d\n", mp->num);
            pthread_mutex_lock(&lock);
            mp->next = head;
            head = mp;
            pthread_mutex_unlock(&lock);
            pthread_cond_signal(&has_product);
            sleep(rand() % 5);
        }
    }
    
    int main()
    {
        pthread_t pid, cid;
    
        srand(time(NULL));
        pthread_create(&pid, NULL, producer, NULL);
        pthread_create(&cid, NULL, consumer, NULL);
        pthread_join(pid, NULL);
        pthread_join(cid, NULL);
        return 0;
    }
    复制代码

    运行结果:

    Produce 1
    Consume 1
    Produce 22
    Produce 756
    Consume 756
    Produce 909
    Produce 941
    Consume 941
    Consume 909
    Consume 22
    Produce 307
    Produce 667
    Produce 567
    Produce 609
    Consume 609
    Produce 892
    Consume 892
    Produce 883

    线程相关函数(7)-sem_post(), sem_wait() 信号量

     

    sem_t
    sem_init
    sem_wait
    sem_trywait
    sem_timedwait
    sem_post
    sem_destroy

    生产者消费者实例:

    复制代码
    #include <stdlib.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <semaphore.h>
    #define NUM 5 int queue[NUM]; sem_t blank_number, product_number;
    void *producer(void *arg) {   int p = 0;   while (1) {     sem_wait(&blank_number);     queue[p] = rand() % 1000 + 1;     printf("Produce %d\n", queue[p]);     sem_post(&product_number);     p = (p+1)%NUM;     sleep(rand()%5);   }
    }
    void *consumer(void *arg) {   int c = 0;   while (1) {     sem_wait(&product_number);     printf("Consume %d\n", queue[c]);     queue[c] = 0;       sem_post(&blank_number);     c = (c+1)%NUM;     sleep(rand()%5);   } }
    int main(int argc, char *argv[]) {   pthread_t pid, cid;   sem_init(&blank_number, 0, NUM);   sem_init(&product_number, 0, 0);   pthread_create(&pid, NULL, producer, NULL);   pthread_create(&cid, NULL, consumer, NULL);   pthread_join(pid, NULL);   pthread_join(cid, NULL);   sem_destroy(&blank_number);   sem_destroy(&product_number);   return 0; }
    复制代码

    读写锁

    读写锁:所有操作者地位等价,所有操作共享资源的方式不等价的,且只划分成了两种地位的操作形式,一种是读操作,一种是写操作。例如张三和李四,无论是谁,都是人,但是可以读和写,无论谁,写操作邮件及更高。读写操作优先级不同,写的优先级更高。同时读写操作时对应两把不同的锁,导致读写操作对待不同锁的权限不同。

    /*
        读写锁的类型 pthread_rwlock_t
        int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
        int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
        int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
        int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
        int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
        int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
        int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    
        案例:8个线程操作同一个全局变量。
        3个线程不定时写这个全局变量,5个线程不定时的读这个全局变量
    */
    
    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    
    // 创建一个共享数据
    int num = 1;
    // pthread_mutex_t mutex;
    pthread_rwlock_t rwlock;
    
    void * writeNum(void * arg) {
    
        while(1) {
            pthread_rwlock_wrlock(&rwlock);
            num++;
            printf("++write, tid : %ld, num : %d\n", pthread_self(), num);
            pthread_rwlock_unlock(&rwlock);
            usleep(100);
        }
    
        return NULL;
    }
    
    void * readNum(void * arg) {
    
        while(1) {
            pthread_rwlock_rdlock(&rwlock);
            printf("===read, tid : %ld, num : %d\n", pthread_self(), num);
            pthread_rwlock_unlock(&rwlock);
            usleep(100);
        }
    
        return NULL;
    }
    
    int main() {
    
       pthread_rwlock_init(&rwlock, NULL);
    
        // 创建3个写线程,5个读线程
        pthread_t wtids[3], rtids[5];
        for(int i = 0; i < 3; i++) {
            pthread_create(&wtids[i], NULL, writeNum, NULL);
        }
    
        for(int i = 0; i < 5; i++) {
            pthread_create(&rtids[i], NULL, readNum, NULL);
        }
    
        // 设置线程分离
        for(int i = 0; i < 3; i++) {
           pthread_detach(wtids[i]);
        }
    
        for(int i = 0; i < 5; i++) {
             pthread_detach(rtids[i]);
        }
    
        pthread_exit(NULL);
    
        pthread_rwlock_destroy(&rwlock);
    
        return 0;
    }
    

    条件变量

    条件变量:只能配合互斥锁用。操作者地位不等价,但操作方式等价的,即无论是哪个操作者执行什么操作,对应的操作都必须用互斥量加锁同步。例如张三和李四,张三是买家李四是卖家,李四没东西了张三又想买就只能等待,但是无论张三买东西还是李四卖东西,具体行为都等价,没有优先级顺序。但是操作者地位不等价,例如生产者与消费者关系。如果消费者将资源消费完,就必须等待生产者生产出新的资源,并通知消费者,消费者才能继续消费。这个过程通过条件变量来控制,但资源消费结束,消费者会通过条件变量提供的方法陷入阻塞,一直等待到生产者生产出资源;而生产者生产出新资源也会唤醒消费者继续消费。被唤醒后的消费者便拥有了和生产者一样的地位,互斥进行各自操作,一直到下一次资源消费结束。

    /*
        条件变量的类型 pthread_cond_t
        int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
        int pthread_cond_destroy(pthread_cond_t *cond);
        int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
            - 等待,调用了该函数,线程会阻塞。;//在该函数内部,开头会先解锁,返回时再加锁。
        int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
            - 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间结束。
        int pthread_cond_signal(pthread_cond_t *cond);
            - 唤醒一个或者多个等待的线程
        int pthread_cond_broadcast(pthread_cond_t *cond);
            - 唤醒所有的等待的线程
    */
    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    // 创建一个互斥量
    pthread_mutex_t mutex;
    // 创建条件变量
    pthread_cond_t cond;
    
    struct Node{
        int num;
        struct Node *next;
    };
    
    // 头结点
    struct Node * head = NULL;
    
    void * producer(void * arg) {
    
        // 不断的创建新的节点,添加到链表中
        while(1) {
            pthread_mutex_lock(&mutex);
            struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
            newNode->next = head;
            head = newNode;
            newNode->num = rand() % 1000;
            printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
            
            // 只要生产了一个,就通知消费者消费
            pthread_cond_signal(&cond);
    
            pthread_mutex_unlock(&mutex);
            usleep(100);
        }
    
        return NULL;
    }
    
    void * customer(void * arg) {
    
        while(1) {
            pthread_mutex_lock(&mutex);
            // 保存头结点的指针
            struct Node * tmp = head;
            // 判断是否有数据
            if(head != NULL) {
                // 有数据
                head = head->next;
                printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
                free(tmp);
                pthread_mutex_unlock(&mutex);
                usleep(100);
            } else {
                // 没有数据,需要等待
                // 当这个函数调用阻塞的时候,会对互斥锁进行解锁,当不阻塞的,继续向下执行,会重新加锁。
                pthread_cond_wait(&cond, &mutex);
                pthread_mutex_unlock(&mutex);
            }
        }
        return  NULL;
    }
    
    int main() {
    
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&cond, NULL);
    
        // 创建5个生产者线程,和5个消费者线程
        pthread_t ptids[5], ctids[5];
    
        for(int i = 0; i < 5; i++) {
            pthread_create(&ptids[i], NULL, producer, NULL);
            pthread_create(&ctids[i], NULL, customer, NULL);
        }
    
        for(int i = 0; i < 5; i++) {
            pthread_detach(ptids[i]);
            pthread_detach(ctids[i]);
        }
    
        while(1) {
            sleep(10);
        }
    
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
    
        pthread_exit(NULL);
    
        return 0;
    }
    
    

    信号量

    信号量:信号量可以用来当成有约束的条件变量,约束就在于使用条件变量时,生产者可以一直生产,无论消费者消费多少,即使消费者一直不消费,生产者已经生产了巨量的资源,生产者还是会继续生产。这会导致资源的堆积膨胀的问题,生产者一直生产,消费者却来不及消费,导致资源越聚越多。想要解决这个问题,必须同时约束生产者与消费者两方、当消费者将资源消费到0时,消费者停止消费;当生产者生产的资源实时剩余量增加到一定程度时,生产者停止生产。例如为生产者设置一个信号量sem_t psem;为消费者设置一个信号量sem_t csem;每次开始生产将生产者可以生产的剩余可生产数量减1,生产结束将消费者的剩余可消费数量加1;每次开始消费将可消费数量减一,每次消费结束将可生产数量加一。
    但是信号量可以单独使用,而条件变量必须配合互斥锁使用,信号量可以当成互斥量使用,互斥量可以看成特殊的信号量,也就是sem范围只有0,1的信号量。

    /*
        信号量的类型 sem_t
        int sem_init(sem_t *sem, int pshared, unsigned int value);
            - 初始化信号量
            - 参数:
                - sem : 信号量变量的地址
                - pshared : 0 用在线程间 ,非0 用在进程间
                - value : 信号量中的值
    
        int sem_destroy(sem_t *sem);
            - 释放资源
    
        int sem_wait(sem_t *sem);
            - 对信号量加锁,调用一次对信号量的值-1,如果值为0,就阻塞
    
        int sem_trywait(sem_t *sem);
    
        int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
        int sem_post(sem_t *sem);
            - 对信号量解锁,调用一次对信号量的值+1
    
        int sem_getvalue(sem_t *sem, int *sval);
    
        sem_t psem;
        sem_t csem;
        init(psem, 0, 8);
        init(csem, 0, 0);
    
        producer() {
            sem_wait(&psem);
            sem_post(&csem)
        }
    
        customer() {
            sem_wait(&csem);
            sem_post(&psem)
        }
    
    */
    
    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <semaphore.h>
    
    // 创建一个互斥量
    pthread_mutex_t mutex;
    // 创建两个信号量
    sem_t psem;
    sem_t csem;
    
    struct Node{
        int num;
        struct Node *next;
    };
    
    // 头结点
    struct Node * head = NULL;
    
    void * producer(void * arg) {
    
        // 不断的创建新的节点,添加到链表中
        while(1) {
            sem_wait(&psem);
            pthread_mutex_lock(&mutex);
            struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
            newNode->next = head;
            head = newNode;
            newNode->num = rand() % 1000;
            printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
            pthread_mutex_unlock(&mutex);
            sem_post(&csem);
        }
    
        return NULL;
    }
    
    void * customer(void * arg) {
    
        while(1) {
            sem_wait(&csem);
            pthread_mutex_lock(&mutex);
            // 保存头结点的指针
            struct Node * tmp = head;
            head = head->next;
            printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
            free(tmp);
            pthread_mutex_unlock(&mutex);
            sem_post(&psem);
           
        }
        return  NULL;
    }
    
    int main() {
    
        pthread_mutex_init(&mutex, NULL);
        sem_init(&psem, 0, 8);
        sem_init(&csem, 0, 0);
    
        // 创建5个生产者线程,和5个消费者线程
        pthread_t ptids[5], ctids[5];
    
        for(int i = 0; i < 5; i++) {
            pthread_create(&ptids[i], NULL, producer, NULL);
            pthread_create(&ctids[i], NULL, customer, NULL);
        }
    
        for(int i = 0; i < 5; i++) {
            pthread_detach(ptids[i]);
            pthread_detach(ctids[i]);
        }
    
        while(1) {
            sleep(10);
        }
    
        pthread_mutex_destroy(&mutex);
    
        pthread_exit(NULL);
    
        return 0;
    }
    
    

    对信号量理解的初始版本:信号量相当于有约束的条件变量,约束就在于使用条件变量时,生产者可以一直生产,无论消费者消费多少,即使消费者一直不消费,生产者已经生产了巨量的资源,生产者还是会继续生产。这会导致资源的堆积膨胀的问题,生产者一直生产,消费者却来不及消费,导致资源越聚越多。想要解决这个问题,就需要约束生产者生产的资源数量和消费者的消费资源数量,使其能够动态平衡在一个数量上。例如限制资源最大值为10,平衡值为7,也就是说当生产者生产的资源堆积了10个,而消费者还未来得及消费时,让生产者停工,等待消费者消费,当消费到了平衡值7时,生产者开始继续生产

  • 相关阅读:
    testNg vs junit 4.X @Test
    lombok+slf4j+logback SLF4J和Logback日志框架详解
    IntelliJ IDEA 当pom.xml更新时,自动加载pom.xml
    运算符重载具体解释
    设计模式之十八:桥接模式(Bridge)
    无限层级的组织机构
    实战Jquery(一)--username校验
    Android错误之--Error retrieving parent for item: No resource found that matches the given name &#39;Theme.A
    hibernate 缓存
    android --多线程下载
  • 原文地址:https://www.cnblogs.com/yipianchuyun/p/15891626.html
Copyright © 2020-2023  润新知