精品国产一区在线_av无码中文字幕无码王_天海翼三点刺激高潮不停_好硬好大好爽视频_欧美高清一区三区在线专区_香蕉黄色片

一口Linux
認證:優質創作者
所在專題目錄 查看專題
Linux中常見同步和互斥機制設計原理
Linux信號量(1)-SYSTEM V
Linux信號量(2)-POSIX 信號量
Linux信號量(3)-內核信號量
兩個線程,兩個互斥鎖,怎么形成一個死循環?
Linux庫概念,動態庫和靜態庫的制作,如何移植第三方庫
作者動態 更多
iptables -m connlimit導致內存不足
2星期前
為什么對技術人員的考核大多都只看加班時間?
3星期前
某通信公司筆試題,你會做幾道?
07-01 21:58
10種初學者最常見的c語言段錯誤實例及原因分析
05-30 12:13
linux系統監控工具小神器:btop
05-17 17:37

Linux信號量(2)-POSIX 信號量

上一章,講述了SYSTEM V信號量,主要運行于進程之間,本章主要介紹POSIX信號量:有名信號量、無名信號量。

POSIX信號量

POSIX信號量進程是3種 IPC(Inter-Process Communication) 機制之一,3種 IPC 機制源于 POSIX.1 的實時擴展。Single UNIX Specification 將3種機制(消息隊列,信號量和共享存儲)置于可選部分中。在 SUSv4 之前,POSIX 信號量接口已經被包含在信號量選項中。在 SUSv4 中,這些接口被移至了基本規范,而消息隊列和共享存儲接口依然是可選的。

POSIX 信號量接口意在解決 XSI 信號量接口的幾個缺陷。

  1. 相比于 XSI 接口,POSIX 信號量接口考慮了更高性能的實現。

  2. POSIX 信號量使用更簡單:沒有信號量集,在熟悉的文件系統操作后一些接口被模式化了。盡管沒有要求一定要在文件系統中實現,但是一些系統的確是這么實現的。

  3. POSIX 信號量在刪除時表現更完美。回憶一下,當一個 XSI 信號量被刪除時,使用這個信號量標識符的操作會失敗,并將 errno 設置成 EIDRM。使用 POSIX 信號量時,操作能繼續正常工作直到該信號量的最后一次引用被釋放。

分類

POSIX信號量是一個sem_t類型的變量,但POSIX有兩種信號量的實現機制:無名信號量和命名信號量。無名信號量只可以在共享內存的情況下,比如實現進程中各個線程之間的互斥和同步,因此無名信號量也被稱作基于內存的信號量;命名信號量通常用于不共享內存的情況下,比如進程間通信。

同時,在創建信號量時,根據信號量取值的不同,POSIX信號量還可以分為:

  • 二值信號量:信號量的值只有0和1,這和互斥量很類似,若資源被鎖住,信號量的值為0,若資源可用,則信號量的值為1;

  • 計數信號量:信號量的值在0到一個大于1的限制值之間,該計數表示可用的資源的個數。

區別

有名信號量和無名信號量的差異在于創建和銷毀的形式上,但是其他工作一樣。

無名信號量只能存在于內存中,要求使用信號量的進程必須能訪問信號量所在的這一塊內存,所以無名信號量只能應用在同一進程內的線程之間(共享進程的內存),或者不同進程中已經映射相同內存內容到它們的地址空間中的線程(即信號量所在內存被通信的進程共享)。意思是說無名信號量只能通過共享內存訪問。

相反,有名信號量可以通過名字訪問,因此可以被任何知道它們名字的進程中的線程使用。

單個進程中使用 POSIX 信號量時,無名信號量更簡單。多個進程間使用 POSIX 信號量時,有名信號量更簡單。

聯系

無論是有名信號量還是無名信號量,都可以通過以下函數進行信號量值操作。

wait(P)

wait 為信號量值減一操作,總共有三個函數,函數原型如下:

#include <semaphore.h>

int sem_wait(sem_t *sem);

int sem_trywait(sem_t *sem);

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

Link with -pthread.這一句表示 gcc 編譯時,要加 -pthread.

返回值:
    若成功,返回 0 ;若出錯,返回-1
  • sem_wait的作用是,若 sem 小于 0 ,則線程阻塞于信號量 sem ,直到 sem 大于 0 ;否則信號量值減1。

  • sem_trywait作用與sem_wait相同,只是此函數不阻塞線程,如果 sem 小于 0,直接返回一個錯誤(錯誤設置為 EAGAIN )。

  • sem_timedwait作用也與sem_wait相同,第二個參數表示阻塞時間,如果 sem 小于 0 ,則會阻塞,參數指定阻塞時間長度。abs_timeout 指向一個結構體,這個結構體由從 1970-01-01 00:00:00 +0000 (UTC) 開始的秒數和納秒數構成。

結構體定義如下:

struct timespec {
    time_t tv_sec;      /* Seconds */
    long   tv_nsec;     /* Nanoseconds [0 .. 999999999] */
}; 

如果指定的阻塞時間到了,但是 sem 仍然小于 0 ,則會返回一個錯誤 (錯誤設置為 ETIMEDOUT )。

post(V)

post 為信號量值加一操作,函數原型如下:

#include <semaphore.h>
int sem_post(sem_t *sem);
Link with -pthread.
返回值:
   若成功,返回 0 ;若出錯,返回-1

無名信號量

接口函數

信號量的函數都以sem_開頭,線程中使用的基本信號函數有4個,他們都聲明在頭文件semaphore.h中,該頭文件定義了用于信號量操作的sem_t類型:

sem_init

該函數用于創建信號量,原型如下:

int sem_init(sem_t *sem, int pshared, unsigned int value);

功能:該函數初始化由sem指向的信號對象,設置它的共享選項,并給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示信號量是當前進程的局部信號量,否則信號量就可以在多個進程間共享,value為sem的初始值。返回值:該函數調用成功返回0,失敗返回-1。

sem_destroy

該函數用于對用完的信號量進行清理,其原型如下:

int sem_destroy(sem_t *sem);

返回值:

成功返回0,失敗返回-1。

sem_getvalue函數

該函數返回當前信號量的值,通過restrict輸出參數返回。如果當前信號量已經上鎖(即同步對象不可用),那么返回值為0,或為負數,其絕對值就是等待該信號量解鎖的線程數。

int sem_getvalue(sem_t *restrict, int *restrict);

使用實例

【實例1】:

#include <time.h>

#include <stdio.h>

#include <errno.h>

#include <unistd.h>

#include <stdlib.h>

#include <assert.h>

#include <signal.h>

#include <semaphore.h>

sem_t sem;

#define handle_error(msg)   do { \
                                perror(msg); \
                                exit(EXIT_FAILURE); \
                            }while (0)
static void handler(int sig){
write(STDOUT_FILENO, "sem_post() from handler\n", 24);
if(sem_post(&sem) == -1)
{
    write(STDERR_FILENO, "sem_post() failed\n", 18);
    _exit(EXIT_FAILURE);
}}
int main(int argc, char *argv[]){
    int s;
    struct timespec ts;
    struct sigaction sa;

    if (argc != 3)
    {
     fprintf(stderr, "Usage: %s <alarm-secs> <wait-secs>\n", argv[0]);
    exit(EXIT_FAILURE);
   }
    
    if (sem_init(&sem, 0, 0) == -1)
        handle_error("sem_init");
    
    /* Establish SIGALRM handler; set alarm timer using argv[1] */
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGALRM, &sa, NULL) == -1)
        handle_error("sigaction");
    
    alarm(atoi(argv[1]));
    
    /* Calculate relative interval as current time plus
      number of seconds given argv[2] */
    
    if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
        handle_error("clock_gettime");
    
    ts.tv_sec += atoi(argv[2]);
    
    printf("main() about to call sem_timedwait()\n");
    while ((s = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR)
        continue;       /* Restart if interrupted by handler */
    
    /* Check what happened */
    if (s == -1)
    {
        if (errno == ETIMEDOUT)
            printf("sem_timedwait() timed out\n");
        else
            perror("sem_timedwait");
    }
    else
    {
        printf("sem_timedwait() succeeded\n");
    }
    
    exit((s == 0) ? EXIT_SUCCESS : EXIT_FAILURE);

}

【實例2】:

#include <time.h>

#include <stdio.h>

#include <errno.h>

#include <unistd.h>

#include <stdlib.h>

#include <assert.h>

#include <signal.h>

#include <semaphore.h>

sem_t sem;
void *func1(void *arg){
    sem_wait(&sem);
    int *running = (int *)arg;
    printf("thread func1 running : %d\n", *running);
    
    pthread_exit(NULL);
}
void *func2(void *arg)
{
    printf("thread func2 running.\n");
    sem_post(&sem);
    
    pthread_exit(NULL);
}
int main(void)
{
    int a = 3;
    sem_init(&sem, 0, 0);
    pthread_t thread_id[2];
    
    pthread_create(&thread_id[0], NULL, func1, (void *)&a);
    printf("main thread running.\n");
    sleep(10);
    pthread_create(&thread_id[1], NULL, func2, (void *)&a);
    printf("main thread still running.\n");
    pthread_join(thread_id[0], NULL);
    pthread_join(thread_id[1], NULL);
    sem_destroy(&sem);
    
    return 0;
}

有名信號量

有時候也叫命名信號量,之所以稱為命名信號量,是因為它有一個名字、一個用戶ID、一個組ID和權限。這些是提供給不共享內存的那些進程使用命名信號量的接口。命名信號量的名字是一個遵守路徑名構造規則的字符串。

接口函數

sem_open函數

該函數用于創建或打開一個命名信號量,其原型如下:

sem_t *sem_open(const char *name, int oflag);sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

參數

  • name是一個標識信號量的字符串。

  • oflag用來確定是創建信號量還是連接已有的信號量。oflag的參數可以為0,O_CREAT或O_EXCL:如果為0,表示打開一個已存在的信號量;如果為O_CREAT,表示如果信號量不存在就創建一個信號量,如果存在則打開被返回,此時mode和value都需要指定;如果為O_CREAT|O_EXCL,表示如果信號量存在則返回錯誤。

  • mode 用于創建信號量時指定信號量的權限位,和open函數一樣,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。

  • value 表示創建信號量時,信號量的初始值。

sem_close函數

該函數用于關閉命名信號量:

int sem_close(sem_t *);

功能:單個程序可以用sem_close函數關閉命名信號量,但是這樣做并不能將信號量從系統中刪除,因為命名信號量在單個程序執行之外是具有持久性的。當進程調用_exit、exit、exec或從main返回時,進程打開的命名信號量同樣會被關閉。

sem_unlink函數功能:sem_unlink函數用于在所有進程關閉了命名信號量之后,將信號量從系統中刪除:

int sem_unlink(const char *name);

信號量操作函數與無名信號量一樣。

使用實例

#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <semaphore.h>
#define SEM_NAME " /sem_name"
sem_t *p_sem;
void *testThread(void *ptr){
    sem_wait(p_sem);
    sleep(2);
    pthread_exit(NULL);}
    int main(void){
    int i = 0;
    pthread_t pid;
    int sem_val = 0;
    p_sem = sem_open(SEM_NAME, O_CREAT, 0555, 5);
    
    if(p_sem == NULL)
    {
        printf("sem_open %s failed!\n", SEM_NAME);
        sem_unlink(SEM_NAME);
        return -1;
    }
    
    for(i = 0; i < 7; i++)
    {
        pthread_create(&pid, NULL, testThread, NULL);
        sleep(1);
        // pthread_join(pid, NULL);  // not needed, or loop
        sem_getvalue(p_sem, &sem_val);
        printf("semaphore value : %d\n", sem_val);
    }
    
    sem_close(p_sem);
    sem_unlink(SEM_NAME);
    
    return 0;
}

命名和無名信號量的持續性

命名信號量是隨內核持續的。當命名信號量創建后,即使當前沒有進程打開某個信號量,它的值依然保持,直到內核重新自舉或調用sem_unlink()刪除該信號量。

無名信號量的持續性要根據信號量在內存中的位置確定:

如果無名信號量是在單個進程內部的數據空間中,即信號量只能在進程內部的各個線程間共享,那么信號量是隨進程的持續性,當進程終止時他也就消失了;

如果無名信號量位于不同進程的共享內存區,因此只要該共享內存區仍然存在,該信號量就會一直存在;所以此時無名信號量是隨內核的持續性。

信號量-互斥量-條件變量

很多時候信號量、互斥量和條件變量都可以在某種應用中使用,那這三者的差異有哪些呢?下面列出了這三者之間的差異:

  • 互斥量必須由給它上鎖的線程解鎖;而信號量不需要由等待它的線程進行掛出,可以在其他進程進行掛出操作;

  • 互斥量要么被鎖住,要么被解開,只有這兩種狀態;而信號量的值可以支持多個進程/線程成功的進行wait操作;

  • 信號量的掛出操作總是被記住,因為信號量有一個計數值,掛出操作總會將該計數值加1,然而當條件變量發送一個信號時,如果沒有線程等待在條件變量,那么該信號就會丟失。

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 2
收藏 1
關注 181
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: 毛片入口 | 亚州av日韩av | 亚洲热视频 | 日韩精品久久中文字幕 | free性videoxxⅹ国产 | 精品福利视频一区二区三区 | 欧美日产一区二区三区在线观看 | 国产婷婷精品任我爽欧美 | 巨乳少妇视频 | 涩综合网 | 亚洲午夜精品无码专区在线观看 | 出差少妇被按摩师玩弄了 | 芳芳的性荡生活第二部 | 污网站在线看 | 中国一级毛片免费观看 | 欧美日韩在线影院 | 三级小说欧洲区亚洲区 | 国产高清在线观看 | 亚洲视频免费在线 | 日本在线视频中文字幕 | 国产精品国产成人国产三级 | 中文亚洲av片在线观看 | 国产xo在线播放视频 | 国产91美女视频 | 韩国三级丰满少妇高潮 | 中文字幕线人 | videos亚洲 | 色噜噜狠狠综曰曰曰 | 天天草夜夜草 | 国产黄色片在线免费观看 | 国产精品日日摸夜夜摸av | 国产成人精品一区二区三区免费 | h成年动漫在线看网站 | 午夜影院在线观看免费 | 在线观看国产精品一区 | 国产精品V片在线观看不卡 啪啪av大全导航福利网址 | 成人免费视频视频在线观看免费 | 亚洲系列第一页 | 久久久久亚洲AV无码尤物 | 337P日本欧洲亚洲大胆 | 男人和女人真曰批视频全过程 |