天天看點

線程的信号量和互斥量線程的信号量線程的互斥量

文章目錄

  • 線程的信号量
    • 初始化信号量:sem_init
    • 減少信号量:sem_wait
    • 增加信号量:sem_post
    • 删除信号量:sem_destroy
    • 代碼示例
  • 線程的互斥量
    • 初始化互斥量:pthread_mutex_init
    • 鎖住互斥量:pthread_mutex_lock
    • 解鎖互斥量:pthread_mutex_unlock
    • 銷毀互斥量:pthread_mutex_destroy
    • 代碼示例

線程的信号量

原理簡介:

線程的信号量和程序的類似,維護一個sem_t類型(本質是一個int類型的)的信号量,不同線程通過判斷信号量的值,來決定是否進行繼續運作,進而控制線程運作的先後順序。比如信号量初始化成0,線程1調用sem_wait阻塞住,等待線程2調用sem_post将限号量增加之後,線程1被喚醒,進而實作線程1、2執行的順序。

使用流程:

  1. sem_init初始化信号量
  2. sem_post增加信号量
  3. sem_wait判斷并減少信号量

初始化信号量:sem_init

sem_init用于初始化信号量的初始值和作用範圍。

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Link with -pthread;
sem: 需要被初始化的信号量對象;
value: 初始值;
pshared: 1)0,表示信号量線程共享,多線程可以共同操作該信号量,要求sem變量的作用域能被多個線程通路到;2)非0,表示信号量程序共享,多程序可以共同操作該信号量,如果是父子程序,要求sem變量的作用域能被多個程序通路到,若父子程序,則可以直接通路,若沒有關系的程序,那麼sem要在共享記憶體中建立;
傳回值: 成功,傳回0;失敗,傳回-1,并置上errno;
           

減少信号量:sem_wait

sem_wait函數判斷信号量是否大于0,如果大于0,則将信号量減一,并且立即傳回,如果小于等于0,就阻塞在該函數,直到信号量大于0。

#include <semaphore.h>
int sem_wait(sem_t *sem);
sem: 待操作的信号量;
傳回值: 成功,傳回0;失敗,傳回-1,并置上errno
           

增加信号量:sem_post

sem_post用于給信号量加1

#include <semaphore.h>
int sem_post(sem_t *sem);
sem: 待操作的信号量;
傳回值: 成功,傳回0;失敗,傳回-1,并置上errno 
           

删除信号量:sem_destroy

#include <semaphore.h>
int sem_destroy(sem_t *sem);
sem: 待操作的信号量;
傳回值: 成功,傳回0;失敗,傳回-1,并置上errno
           

代碼示例

線程1先被建立,但是阻塞在信号量上,線程2後被建立,被運作後将信号量增加,然後線程1識别到信号量大于零,才執行後面的步驟。

#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

sem_t sem;

void * func1(void *arg)
{
        int ret;
        ret = sem_wait(&sem);
        if (ret != 0) {
                perror("sem_wait: ");
                return NULL;
        }
        printf("%s: pthread id: %ul\n", __func__, pthread_self());
}

void * func2(void *arg)
{
        int ret;
        printf("%s: pthread id: %ul\n", __func__, pthread_self());
        ret = sem_post(&sem);
        if (ret != 0) {
                perror("sem_post: ");
                return NULL;
        }
}

int
main(int argc, char **argv)
{
        int ret;
        pthread_t p1, p2;

        ret = sem_init(&sem, 0, 0);
        if (ret < 0) {
                perror("sem_init: ");
                return -1;
        }

        ret = pthread_create(&p1, NULL, &func1, NULL);
        if (ret != 0) {
                perror("pthread_create: ");
                return -1;
        }
        sleep(5);
        ret = pthread_create(&p2, NULL, &func2, NULL);
        if (ret != 0) {
                perror("pthread_create: ");
                return -1;
        }
        sleep(1);
        return 0;

}
           

線程的互斥量

原理簡介:

  • 互斥量底層也是通過鎖實作的,第一個線程通路互斥量的時候對互斥量加鎖,後續線程加鎖互斥量的時候會被阻塞,直到鎖被釋放
  • 互斥量在POSIX中定義
  • 互斥量是一種特殊的信号量,信号量是一個int數值,可以随意大小,互斥量隻有0和1

使用流程:

  1. 初始化互斥量
  2. 鎖住互斥量
  3. 解鎖互斥量
  4. 銷毀互斥量

初始化互斥量:pthread_mutex_init

互斥量用之前必須初始化:

//初始化方法1:使用預設屬性,必須在定義的時候初始化,不可以先定義後初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//初始化方法2:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);
mutex: 待初始化的互斥量;
attr: 參數,可以直接使用NULL;
傳回值: 成功,傳回0,失敗,傳回非0,并置上errno
           

鎖住互斥量:pthread_mutex_lock

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
mutex: 待鎖住的互斥量;
傳回值: 成功,傳回0,失敗,傳回非0,并置上errno
           

解鎖互斥量:pthread_mutex_unlock

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex: 待解鎖的互斥量;
傳回值: 成功,傳回0,失敗,傳回非0,并置上errno;
           

銷毀互斥量:pthread_mutex_destroy

互斥量用完了之後要釋放

#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex: 待銷毀的互斥量;
傳回值: 成功,傳回0,失敗,傳回非0,并置上errno;
           

代碼示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void * func1(void *arg)
{
        int ret;
        ret = pthread_mutex_lock(&mutex);
    if (ret != 0){
        perror("pthread_mutex_lock: ");
        return NULL;
    }
        printf("%s: pthread id: %ul\n", __func__, pthread_self());
        pthread_mutex_destroy(&mutex);
}

void * func2(void *arg)
{
        int ret;
        printf("%s: pthread id: %ul\n", __func__, pthread_self());
}

int
main(int argc, char **argv)
{
        int ret;
        pthread_t p1, p2;

        //ret = pthread_mutex_init(&mutex, NULL);
        //if (ret != 0) {
        //      perror("pthread_mutex_init: ");
        //      return -1;
        //}

        ret = pthread_mutex_lock(&mutex);
        if (ret != 0){
                perror("pthread_mutex_lock: ");
                return -1;
        }

        ret = pthread_create(&p1, NULL, &func1, NULL);
        if (ret != 0) {
                perror("pthread_create: ");
                return -1;
        }
        sleep(5);
        ret = pthread_create(&p2, NULL, &func2, NULL);
        if (ret != 0) {
                perror("pthread_create: ");
                return -1;
        }
        sleep(1);
        ret = pthread_mutex_unlock(&mutex);
    if (ret != 0){
        perror("pthread_mutex_lock: ");
        return -1;
    }
        sleep(1);
        return 0;
}
           

繼續閱讀