国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux和windows進(jìn)程同步與線程同步那些事兒(五):Linux下進(jìn)程同步

這篇具有很好參考價值的文章主要介紹了Linux和windows進(jìn)程同步與線程同步那些事兒(五):Linux下進(jìn)程同步。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

Linux和windows進(jìn)程同步與線程同步那些事兒(一)
Linux和windows進(jìn)程同步與線程同步那些事兒(二): windows線程同步詳解示例
Linux和windows進(jìn)程同步與線程同步那些事兒(三): Linux線程同步詳解示例
Linux和windows進(jìn)程同步與線程同步那些事兒(四):windows 下進(jìn)程同步
Linux和windows進(jìn)程同步與線程同步那些事兒(五):Linux下進(jìn)程同步

在Linux中,進(jìn)程同步可以通過多種機(jī)制來實(shí)現(xiàn),其中最常見的包括信號量(semaphore)、共享內(nèi)存(shared memory)、管道(pipe)、消息隊列(message queue)和文件鎖(file lock)等。

1. 信號量(Semaphore):

信號量是一種經(jīng)典的進(jìn)程同步機(jī)制,它可以用于控制對共享資源的訪問。
在Linux中,可以使用sem_t類型的信號量來實(shí)現(xiàn)進(jìn)程同步。

在Linux下,可以使用信號量實(shí)現(xiàn)多進(jìn)程之間的同步。信號量是一個計數(shù)器,用于多個進(jìn)程之間共享資源的同步操作。

下面是一個使用信號量進(jìn)行多處理器同步的C++代碼示例:

#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

// 定義信號量的鍵值
#define KEY 123456

// 定義信號量的個數(shù)
#define NUM_SEMS 1

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    // 創(chuàng)建信號量
    int semid = semget(KEY, NUM_SEMS, IPC_CREAT | 0666);
    if (semid == -1) {
        std::cerr << "Failed to create semaphore" << std::endl;
        return 1;
    }

    // 初始化信號量
    union semun arg;
    arg.val = 0;
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        std::cerr << "Failed to initialize semaphore" << std::endl;
        return 1;
    }

    // 創(chuàng)建子進(jìn)程
    pid_t pid = fork();
    if (pid == -1) {
        std::cerr << "Failed to fork process" << std::endl;
        return 1;
    } else if (pid == 0) {
        // 子進(jìn)程和父進(jìn)程通過信號量進(jìn)行同步操作

        // P操作,等待信號量計數(shù)器大于0
        struct sembuf sop;
        sop.sem_num = 0;
        sop.sem_op = -1;
        sop.sem_flg = 0;
        if (semop(semid, &sop, 1) == -1) {
            std::cerr << "Failed to perform P operation" << std::endl;
            return 1;
        }

        // 輸出一段文字
        std::cout << "Child process output" << std::endl;

        // V操作,增加信號量計數(shù)器
        sop.sem_op = 1;
        if (semop(semid, &sop, 1) == -1) {
            std::cerr << "Failed to perform V operation" << std::endl;
            return 1;
        }
    } else {
        // 父進(jìn)程和子進(jìn)程通過信號量進(jìn)行同步操作

        // 輸出一段文字
        std::cout << "Parent process output" << std::endl;

        // V操作,增加信號量計數(shù)器
        struct sembuf sop;
        sop.sem_num = 0;
        sop.sem_op = 1;
        sop.sem_flg = 0;
        if (semop(semid, &sop, 1) == -1) {
            std::cerr << "Failed to perform V operation" << std::endl;
            return 1;
        }

        // P操作,等待信號量計數(shù)器大于0
        sop.sem_op = -1;
        if (semop(semid, &sop, 1) == -1) {
            std::cerr << "Failed to perform P operation" << std::endl;
            return 1;
        }
    }

    // 刪除信號量
    if (semctl(semid, 0, IPC_RMID) == -1) {
        std::cerr << "Failed to remove semaphore" << std::endl;
        return 1;
    }

    return 0;
}

在上面的代碼示例中,首先使用semget函數(shù)創(chuàng)建了一個信號量集,通過指定鍵值和信號量的個數(shù)來創(chuàng)建。然后使用semctl函數(shù)初始化了信號量的計數(shù)器為0。接著通過fork函數(shù)創(chuàng)建了一個子進(jìn)程。

在子進(jìn)程中,使用semop函數(shù)進(jìn)行P操作,即等待信號量計數(shù)器大于0;然后輸出一段文字;再使用semop函數(shù)進(jìn)行V操作,即增加信號量計數(shù)器。

在父進(jìn)程中,首先輸出一段文字;然后使用semop函數(shù)進(jìn)行V操作;最后使用semop函數(shù)進(jìn)行P操作。

這樣,父進(jìn)程和子進(jìn)程通過信號量的P操作和V操作進(jìn)行同步,保證了子進(jìn)程的輸出一定在父進(jìn)程的輸出之后。

最后,使用semctl函數(shù)刪除了創(chuàng)建的信號量集。

運(yùn)行代碼示例,可以看到父進(jìn)程先輸出一段文字,然后子進(jìn)程再輸出一段文字,證明了通過信號量實(shí)現(xiàn)了多進(jìn)程的同步。

需要注意的是,上述代碼示例只使用了一個信號量來進(jìn)行同步,如果需要更復(fù)雜的同步操作,可以使用多個信號量來實(shí)現(xiàn)。此外,需要保證在使用信號量之前先創(chuàng)建信號量,并在使用完畢后刪除信號量。


2. 共享內(nèi)存(Shared Memory):

共享內(nèi)存允許多個進(jìn)程訪問同一塊內(nèi)存區(qū)域,從而實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)共享和通信。
在Linux中,可以使用shmgetshmat等系統(tǒng)調(diào)用來創(chuàng)建和訪問共享內(nèi)存區(qū)域。

代碼示例1:

在Linux下,使用共享內(nèi)存進(jìn)行多進(jìn)程間的同步一般會用到信號量(semaphore)來進(jìn)行進(jìn)程間的互斥和同步操作。下面是一個使用C進(jìn)行編寫的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <unistd.h>

// 定義信號量的操作結(jié)構(gòu)體
union semun {
  int val;
  struct semid_ds *buf;
  unsigned short int *array;
  struct seminfo *__buf;
};

// 定義共享內(nèi)存的大小
#define SHM_SIZE 1024

// 定義信號量操作函數(shù)
int sem_op(int semid, int sem_num, int op) {
  struct sembuf semop = {sem_num, op, SEM_UNDO};
  return semop(semid, &semop, 1);
}

int main() {
  key_t key;
  int shmid, semid;
  char *shm, *s;

  // 創(chuàng)建key值
  key = ftok(".", 'S');
  if (key == -1) {
    perror("ftok error");
    exit(1);
  }

  // 創(chuàng)建共享內(nèi)存
  shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
  if (shmid == -1) {
    perror("shmget error");
    exit(1);
  }

  // 關(guān)聯(lián)共享內(nèi)存
  shm = shmat(shmid, NULL, 0);
  if (shm == (char *)-1) {
    perror("shmat error");
    exit(1);
  }

  // 創(chuàng)建信號量
  semid = semget(key, 1, IPC_CREAT | 0666);
  if (semid == -1) {
    perror("semget error");
    exit(1);
  }

  // 初始化信號量
  union semun sem_val;
  sem_val.val = 1;
  if (semctl(semid, 0, SETVAL, sem_val) == -1) {
    perror("semctl error");
    exit(1);
  }

  // 多進(jìn)程同步
  pid_t pid = fork();

  if (pid == -1) {
    perror("fork error");
    exit(1);
  } else if (pid == 0) { // 子進(jìn)程
    // P 操作
    if (sem_op(semid, 0, -1) == -1) {
      perror("sem_op error");
      exit(1);
    }

    // 操作共享內(nèi)存
    s = shm;
    for (char c = 'a'; c <= 'z'; c++) {
      *s++ = c;
      usleep(10000);
    }

    // V 操作
    if (sem_op(semid, 0, 1) == -1) {
      perror("sem_op error");
      exit(1);
    }

    // 分離共享內(nèi)存
    if (shmdt(shm) == -1) {
      perror("shmdt error");
      exit(1);
    }

    exit(0);
  } else { // 父進(jìn)程
    // P 操作
    if (sem_op(semid, 0, -1) == -1) {
      perror("sem_op error");
      exit(1);
    }

    // 讀取并輸出共享內(nèi)存
    s = shm;
    while (*s != '\0') {
      putchar(*s++);
      usleep(10000);
    }
    putchar('\n');

    // V 操作
    if (sem_op(semid, 0, 1) == -1) {
      perror("sem_op error");
      exit(1);
    }

    // 刪除共享內(nèi)存
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
      perror("shmctl error");
      exit(1);
    }

    // 刪除信號量
    if (semctl(semid, IPC_RMID, 0) == -1) {
      perror("semctl error");
      exit(1);
    }

    exit(0);
  }

  return 0;
}

這段代碼通過創(chuàng)建共享內(nèi)存和信號量來實(shí)現(xiàn)多進(jìn)程間的同步,其中子進(jìn)程將字母逐個寫入共享內(nèi)存,父進(jìn)程從共享內(nèi)存中讀取并輸出字母。

首先,使用ftok函數(shù)創(chuàng)建一個唯一的key值,用于共享內(nèi)存和信號量的標(biāo)識。然后,使用shmget函數(shù)創(chuàng)建共享內(nèi)存,指定大小為SHM_SIZE。接著,使用shmat函數(shù)關(guān)聯(lián)共享內(nèi)存并返回一個指向共享內(nèi)存的指針。再然后,使用semget函數(shù)創(chuàng)建一個信號量,并使用semctl函數(shù)初始化信號量的值為1。

接下來,使用fork函數(shù)創(chuàng)建一個子進(jìn)程。在子進(jìn)程中,使用sem_op函數(shù)進(jìn)行P操作(信號量減1),然后通過指針s操作共享內(nèi)存,將字母逐個寫入共享內(nèi)存。最后,使用sem_op函數(shù)進(jìn)行V操作(信號量加1),然后使用shmdt函數(shù)分離共享內(nèi)存。

在父進(jìn)程中,使用sem_op函數(shù)進(jìn)行P操作,然后通過指針s從共享內(nèi)存中讀取并輸出字母,直到遇到結(jié)束符’\0’。然后,使用sem_op函數(shù)進(jìn)行V操作。最后,使用shmctl函數(shù)刪除共享內(nèi)存,使用semctl函數(shù)刪除信號量。

代碼示例2:

以下是一個使用共享內(nèi)存實(shí)現(xiàn)多進(jìn)程同步的示例代碼,分為A和B兩個程序:

程序A:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/wait.h>

#define SHM_KEY 1234
#define SHM_SIZE 256

int main() {
    // 創(chuàng)建共享內(nèi)存
    int shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    // 連接共享內(nèi)存
    char* shared_memory = (char*)shmat(shmid, NULL, 0);
    if (shared_memory == (char*)-1) {
        perror("shmat");
        exit(1);
    }

    // 寫入數(shù)據(jù)到共享內(nèi)存
    sprintf(shared_memory, "Hello, World!");

    // 創(chuàng)建子進(jìn)程
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    } else if (pid == 0) {
        // 子進(jìn)程等待一段時間
        sleep(1);

        // 父子進(jìn)程間同步,等待父進(jìn)程寫入數(shù)據(jù)
        while (shared_memory[0] == '\0') {
            sleep(1);
        }

        // 讀取并打印共享內(nèi)存中的數(shù)據(jù)
        printf("Data in shared memory: %s\n", shared_memory);

        // 斷開連接共享內(nèi)存
        if (shmdt(shared_memory) == -1) {
            perror("shmdt");
            exit(1);
        }

        exit(0);
    } else {
        // 等待子進(jìn)程結(jié)束
        wait(NULL);

        // 斷開連接共享內(nèi)存
        if (shmdt(shared_memory) == -1) {
            perror("shmdt");
            exit(1);
        }

        // 刪除共享內(nèi)存
        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
            perror("shmctl");
            exit(1);
        }
    }

    return 0;
}

程序B:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>

#define SHM_KEY 1234
#define SHM_SIZE 256

int main() {
    // 獲取共享內(nèi)存的ID
    int shmid = shmget(SHM_KEY, SHM_SIZE, 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    // 連接共享內(nèi)存
    char* shared_memory = (char*)shmat(shmid, NULL, 0);
    if (shared_memory == (char*)-1) {
        perror("shmat");
        exit(1);
    }

    // 等待父進(jìn)程寫入數(shù)據(jù)
    while (shared_memory[0] == '\0') {
        sleep(1);
    }

    // 讀取并打印共享內(nèi)存中的數(shù)據(jù)
    printf("Data in shared memory: %s\n", shared_memory);

    // 斷開連接共享內(nèi)存
    if (shmdt(shared_memory) == -1) {
        perror("shmdt");
        exit(1);
    }

    return 0;
}

以上代碼展示了一個簡單的多進(jìn)程同步示例。程序A創(chuàng)建了共享內(nèi)存并將數(shù)據(jù)寫入其中,然后創(chuàng)建了一個子進(jìn)程程序B。程序B連接到共享內(nèi)存,等待程序A寫入數(shù)據(jù)后讀取并打印。程序A和程序B通過共享內(nèi)存進(jìn)行了數(shù)據(jù)的同步。

注意代碼中的關(guān)鍵步驟:

  1. 使用shmget函數(shù)創(chuàng)建共享內(nèi)存,指定一個唯一的鍵值和大小。
  2. 使用shmat函數(shù)連接共享內(nèi)存,獲取指向共享內(nèi)存的指針。
  3. 子進(jìn)程通過輪詢等待共享內(nèi)存中的數(shù)據(jù),直到非空。
  4. 父進(jìn)程和子進(jìn)程完成后,使用shmdt函數(shù)斷開與共享內(nèi)存的連接。
  5. 父進(jìn)程使用shmctl函數(shù)刪除共享內(nèi)存。

這樣,兩個進(jìn)程就能夠?qū)崿F(xiàn)通過共享內(nèi)存進(jìn)行數(shù)據(jù)同步了。


3. 管道(Pipe):

管道是一種單向的通信機(jī)制,可以用于實(shí)現(xiàn)具有父子關(guān)系的進(jìn)程間通信。
在Linux中,可以使用pipe系統(tǒng)調(diào)用來創(chuàng)建管道。
在Linux下,使用管道進(jìn)行多進(jìn)程同步一般會用到父子進(jìn)程間的通信機(jī)制。下面是一個使用C進(jìn)行編寫的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
  int fd[2];
  pid_t pid;
  char buf[100];

  // 創(chuàng)建管道
  if (pipe(fd) == -1) {
    perror("pipe error");
    exit(1);
  }

  // 創(chuàng)建子進(jìn)程
  pid = fork();

  if (pid == -1) {
    perror("fork error");
    exit(1);
  } else if (pid == 0) { // 子進(jìn)程
    close(fd[0]); // 關(guān)閉讀端

    // 在子進(jìn)程中向管道寫入數(shù)據(jù)
    char *str = "Hello from child process!";
    write(fd[1], str, strlen(str) + 1);
    printf("Child process writes to pipe: %s\n", str);

    close(fd[1]); // 關(guān)閉寫端
    exit(0);
  } else { // 父進(jìn)程
    close(fd[1]); // 關(guān)閉寫端

    // 在父進(jìn)程中從管道讀取數(shù)據(jù)
    read(fd[0], buf, sizeof(buf));
    printf("Parent process reads from pipe: %s\n", buf);

    close(fd[0]); // 關(guān)閉讀端
    exit(0);
  }

  return 0;
}

這段代碼通過創(chuàng)建管道來實(shí)現(xiàn)父子進(jìn)程間的數(shù)據(jù)傳輸和同步,其中子進(jìn)程向管道寫入數(shù)據(jù),父進(jìn)程從管道讀取數(shù)據(jù)并輸出。

首先,使用pipe函數(shù)創(chuàng)建一個管道,返回的fd數(shù)組包含兩個文件描述符,fd[0]用于讀取數(shù)據(jù),fd[1]用于寫入數(shù)據(jù)。

接下來,使用fork函數(shù)創(chuàng)建一個子進(jìn)程。在子進(jìn)程中,關(guān)閉fd[0]讀端,使用write函數(shù)向管道寫入數(shù)據(jù),然后關(guān)閉fd[1]寫端。

在父進(jìn)程中,關(guān)閉fd[1]寫端,使用read函數(shù)從管道中讀取數(shù)據(jù),然后輸出到屏幕上。最后,關(guān)閉fd[0]讀端。

以上就是使用管道進(jìn)行多進(jìn)程同步的C代碼示例及詳細(xì)講解。通過在父子進(jìn)程間傳輸數(shù)據(jù)進(jìn)行同步,父進(jìn)程從管道中讀取數(shù)據(jù)時會阻塞,直到子進(jìn)程寫入數(shù)據(jù)到管道中。這樣就實(shí)現(xiàn)了簡單的多進(jìn)程同步。


4. 消息隊列(Message Queue):

消息隊列允許進(jìn)程之間通過消息進(jìn)行通信,可以實(shí)現(xiàn)進(jìn)程間的異步通信。
在Linux中,可以使用msgget、msgsndmsgrcv等系統(tǒng)調(diào)用來創(chuàng)建和操作消息隊列。

在Linux下,可以使用消息隊列來實(shí)現(xiàn)多進(jìn)程之間的同步。消息隊列是一種進(jìn)程間通信的方式,可以在不同進(jìn)程之間傳遞數(shù)據(jù)。下面是一個示例,展示了如何使用消息隊列實(shí)現(xiàn)多進(jìn)程同步。

程序A:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSG_SIZE 128

// 定義消息結(jié)構(gòu)體
struct msg_buffer {
    long msg_type;
    char msg_text[MSG_SIZE];
};

int main() {
    key_t key;
    int msg_id;
    struct msg_buffer message;

    // 生成唯一的key
    key = ftok("msg_queue_example", 65);

    // 創(chuàng)建消息隊列,如果已經(jīng)存在則打開
    msg_id = msgget(key, 0666 | IPC_CREAT);
    if (msg_id == -1) {
        perror("msgget");
        return -1;
    }

    // 接收來自程序B的消息
    msgrcv(msg_id, &message, MSG_SIZE, 1, 0);
    printf("Received message: %s\n", message.msg_text);

    // 向程序B發(fā)送消息
    message.msg_type = 2;
    sprintf(message.msg_text, "Hello from A");
    msgsnd(msg_id, &message, sizeof(message), 0);

    printf("Message sent: %s\n", message.msg_text);

    // 刪除消息隊列
    msgctl(msg_id, IPC_RMID, NULL);

    return 0;
}

程序B:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSG_SIZE 128

// 定義消息結(jié)構(gòu)體
struct msg_buffer {
    long msg_type;
    char msg_text[MSG_SIZE];
};

int main() {
    key_t key;
    int msg_id;
    struct msg_buffer message;

    // 生成唯一的key
    key = ftok("msg_queue_example", 65);

    // 連接到消息隊列
    msg_id = msgget(key, 0666 | IPC_CREAT);
    if (msg_id == -1) {
        perror("msgget");
        return -1;
    }

    // 向程序A發(fā)送消息
    message.msg_type = 1;
    sprintf(message.msg_text, "Hello from B");
    msgsnd(msg_id, &message, sizeof(message), 0);

    printf("Message sent: %s\n", message.msg_text);

    // 接收來自程序A的消息
    msgrcv(msg_id, &message, MSG_SIZE, 2, 0);
    printf("Received message: %s\n", message.msg_text);

    return 0;
}

在程序A中,首先調(diào)用ftok函數(shù)生成一個唯一的key,用于創(chuàng)建消息隊列。然后使用msgget函數(shù)創(chuàng)建或打開一個消息隊列,如果隊列已經(jīng)存在,則打開;如果隊列不存在,則創(chuàng)建一個新的隊列。然后使用msgrcv函數(shù)接收來自程序B的消息,并打印接收到的消息內(nèi)容。接下來,向程序B發(fā)送一個消息,使用msgsnd函數(shù)。最后,使用msgctl函數(shù)刪除消息隊列。

在程序B中,也是首先調(diào)用ftok函數(shù)生成一個唯一的key,用于連接到消息隊列。然后使用msgget函數(shù)連接到消息隊列。接下來,向程序A發(fā)送一個消息,使用msgsnd函數(shù)。然后使用msgrcv函數(shù)接收來自程序A的消息,并打印接收到的消息內(nèi)容。

這個示例展示了兩個進(jìn)程之間如何使用消息隊列進(jìn)行通信和同步。程序A和程序B分別使用不同的消息類型作為消息的標(biāo)志,以便接收和發(fā)送不同類型的消息。msgrcvmsgsnd函數(shù)用于接收和發(fā)送消息。


5. 文件鎖(File Lock):

文件鎖可以用于控制對文件的訪問,從而實(shí)現(xiàn)進(jìn)程間的同步。
在Linux中,可以使用fcntl系統(tǒng)調(diào)用來對文件進(jìn)行加鎖和解鎖操作。
在Linux下,可以使用文件鎖(fcntl)來實(shí)現(xiàn)多進(jìn)程之間的同步。文件鎖可以用于進(jìn)程間共享的文件,通過對文件進(jìn)行加鎖和解鎖,可以實(shí)現(xiàn)進(jìn)程之間的互斥訪問。下面是一個示例,展示了如何使用文件鎖實(shí)現(xiàn)多進(jìn)程同步。

程序A:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd;
    struct flock lock;

    // 打開共享文件
    fd = open("shared_file.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // 加鎖
    lock.l_type = F_WRLCK;   // 寫鎖
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;          // 鎖定整個文件

    if (fcntl(fd, F_SETLKW, &lock) == -1) {
        perror("fcntl");
        return -1;
    }

    printf("A: File locked\n");
    sleep(5); // 模擬處理時間

    // 解鎖
    lock.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("fcntl");
        return -1;
    }

    printf("A: File unlocked\n");

    return 0;
}

程序B:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd;
    struct flock lock;

    // 打開共享文件
    fd = open("shared_file.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // 加鎖
    lock.l_type = F_WRLCK;   // 寫鎖
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;          // 鎖定整個文件

    if (fcntl(fd, F_SETLKW, &lock) == -1) {
        perror("fcntl");
        return -1;
    }

    printf("B: File locked\n");
    sleep(5); // 模擬處理時間

    // 解鎖
    lock.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("fcntl");
        return -1;
    }

    printf("B: File unlocked\n");

    return 0;
}

在程序A中,首先使用open函數(shù)打開共享文件,如果文件不存在則創(chuàng)建。然后定義一個struct flock結(jié)構(gòu)體用于加鎖和解鎖。接下來,設(shè)置鎖的類型為寫鎖,通過fcntl函數(shù)的F_SETLKW參數(shù)來加鎖,并指定鎖定的范圍為整個文件。等待一段時間(這里用sleep(5)模擬處理時間)。最后,設(shè)置鎖的類型為解鎖,通過fcntl函數(shù)來解鎖。

程序B的邏輯與程序A類似,首先使用open函數(shù)打開共享文件,然后設(shè)置鎖的類型為寫鎖,通過fcntl函數(shù)的F_SETLKW參數(shù)來加鎖,并指定鎖定的范圍為整個文件。等待一段時間,最后解鎖。

這個示例展示了兩個進(jìn)程之間如何使用文件鎖實(shí)現(xiàn)同步。進(jìn)程A和進(jìn)程B都對共享文件進(jìn)行加鎖,當(dāng)一個進(jìn)程已經(jīng)持有鎖時,另一個進(jìn)程會在fcntl函數(shù)上阻塞,直到持有鎖的進(jìn)程釋放鎖。這樣保證了進(jìn)程A和進(jìn)程B可以交替地對共享資源進(jìn)行訪問,實(shí)現(xiàn)了同步。

拓展講解:

既然說到了文件鎖,有必要在此強(qiáng)調(diào)下讀鎖、寫鎖和讀寫鎖,對于不同的應(yīng)用場景,合理選擇文件鎖,可以優(yōu)化程序執(zhí)行效率。
在Linux中,文件鎖(fcntl)包括讀鎖和寫鎖兩種類型,以及讀寫鎖(pthread_rwlock)。

  1. 讀鎖(Shared Lock):

    • 多個進(jìn)程可以同時持有讀鎖。
    • 讀鎖是共享的,多個進(jìn)程可以同時讀取文件。
    • 當(dāng)有進(jìn)程持有寫鎖時,請求讀鎖的進(jìn)程會被阻塞,直到所有寫鎖都被釋放。
  2. 寫鎖(Exclusive Lock):

    • 寫鎖是獨(dú)占的,同一時間只能有一個進(jìn)程持有寫鎖。
    • 寫鎖保證了獨(dú)占的訪問權(quán)限,其他進(jìn)程無法讀取或?qū)懭胛募?/li>
    • 當(dāng)有進(jìn)程持有讀鎖或?qū)戞i時,請求寫鎖的進(jìn)程會被阻塞,直到所有讀鎖和寫鎖都被釋放。
  3. 讀寫鎖(Read-Write Lock):

    • 讀寫鎖是一種更高級別的文件鎖,提供了更細(xì)粒度的控制。
    • 讀寫鎖允許多個進(jìn)程同時持有讀鎖,但只允許一個進(jìn)程持有寫鎖。
    • 當(dāng)有進(jìn)程持有寫鎖時,請求讀鎖或?qū)戞i的進(jìn)程都會被阻塞,直到寫鎖被釋放。

下面是一個使用文件鎖和讀寫鎖的示例:

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

// 文件鎖示例
void fileLockExample() {
    int fd;
    struct flock lock;

    // 打開文件
    fd = open("shared_file.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open");
        return;
    }

    // 加寫鎖
    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    if (fcntl(fd, F_SETLKW, &lock) == -1) {
        perror("lock");
        return;
    }

    printf("File locked\n");
    sleep(5); // 模擬處理時間

    // 解鎖
    lock.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("unlock");
        return;
    }

    printf("File unlocked\n");

    close(fd);
}

// 讀寫鎖示例
pthread_rwlock_t rwlock;

void* reader(void* arg) {
    pthread_rwlock_rdlock(&rwlock);
    printf("Reader: Reading shared resource\n");
    sleep(3); // 模擬讀取時間
    pthread_rwlock_unlock(&rwlock);
    printf("Reader: Finished reading\n");
    return NULL;
}

void* writer(void* arg) {
    pthread_rwlock_wrlock(&rwlock);
    printf("Writer: Writing to shared resource\n");
    sleep(3); // 模擬寫入時間
    pthread_rwlock_unlock(&rwlock);
    printf("Writer: Finished writing\n");
    return NULL;
}

void rwLockExample() {
    pthread_t readerThread1, readerThread2, writerThread;

    pthread_rwlock_init(&rwlock, NULL);

    // 創(chuàng)建讀者線程
    pthread_create(&readerThread1, NULL, reader, NULL);
    pthread_create(&readerThread2, NULL, reader, NULL);

    // 創(chuàng)建寫者線程
    pthread_create(&writerThread, NULL, writer, NULL);

    // 等待線程結(jié)束
    pthread_join(readerThread1, NULL);
    pthread_join(readerThread2, NULL);
    pthread_join(writerThread, NULL);

    pthread_rwlock_destroy(&rwlock);
}

int main() {
    printf("File Lock Example:\n");
    fileLockExample();

    printf("\nRead-Write Lock Example:\n");
    rwLockExample();

    return 0;
}

在示例中,fileLockExample函數(shù)展示了如何使用fcntl函數(shù)實(shí)現(xiàn)文件鎖。首先打開共享文件,在加鎖之前設(shè)置鎖的類型為寫鎖。然后,通過fcntl函數(shù)的F_SETLKW參數(shù)來加鎖,使用F_UNLCK參數(shù)來解鎖。

rwLockExample函數(shù)展示了如何使用讀寫鎖(pthread_rwlock)實(shí)現(xiàn)多線程同步。首先初始化讀寫鎖,然后創(chuàng)建讀者線程和寫者線程。讀者線程使用pthread_rwlock_rdlock函數(shù)加讀鎖,寫者線程使用pthread_rwlock_wrlock函數(shù)加寫鎖。最后,使用pthread_rwlock_unlock函數(shù)解鎖,并銷毀讀寫鎖。

文件鎖和讀寫鎖總結(jié):

  • 文件鎖提供了對共享文件的互斥訪問,讀鎖和寫鎖之間的關(guān)系是互斥的。
  • 讀寫鎖提供了更高級別的文件訪問控制,允許多個進(jìn)程同時讀取文件,但只允許一個進(jìn)程寫入文件。

幾種進(jìn)程間同步方式的優(yōu)缺點(diǎn)比較

linux進(jìn)程間同步可以使用信號量、共享內(nèi)存、管道、消息隊列和文件鎖等機(jī)制。下面是它們的使用場景及優(yōu)缺點(diǎn)的比較:

1. 信號量:

  • 使用場景:適用于進(jìn)程間的互斥和同步操作,如控制臨界區(qū)訪問、資源的分配和釋放等。
  • 優(yōu)點(diǎn):簡單易用,適用于進(jìn)程間的基本同步和互斥操作。
  • 缺點(diǎn):需要手動編寫代碼來保證進(jìn)程對信號量的正確使用,容易出錯。不適用于跨網(wǎng)絡(luò)的進(jìn)程通信。

2. 共享內(nèi)存:

  • 使用場景:適用于大量數(shù)據(jù)共享和頻繁的數(shù)據(jù)交換,如圖像、音頻或視頻數(shù)據(jù)的處理。
  • 優(yōu)點(diǎn):高效,進(jìn)程可以直接訪問共享內(nèi)存區(qū)域,無需數(shù)據(jù)的拷貝。
  • 缺點(diǎn):需要進(jìn)行進(jìn)程間的同步,以避免競態(tài)條件和數(shù)據(jù)一致性問題。對內(nèi)存管理要求較高,可能會導(dǎo)致內(nèi)存泄漏或懸掛進(jìn)程。

3. 管道:

  • 使用場景:適用于父子進(jìn)程間的通信,管道只能在具有父子關(guān)系的進(jìn)程之間使用。
  • 優(yōu)點(diǎn):簡單易用,無需手動同步,通過文件描述符進(jìn)行進(jìn)程間通信。
  • 缺點(diǎn):僅適用于具有父子關(guān)系的進(jìn)程,只能實(shí)現(xiàn)單向通信。

4. 消息隊列:

  • 使用場景:適用于不同進(jìn)程間的異步通信,如進(jìn)程間的命令、事件、消息傳遞等。
  • 優(yōu)點(diǎn):可以實(shí)現(xiàn)多對多的通信,不需要進(jìn)程具有父子關(guān)系。具有高度的靈活性和可擴(kuò)展性。
  • 缺點(diǎn):數(shù)據(jù)的大小受限,對于大量數(shù)據(jù)的傳輸可能不太高效。

5. 文件鎖:

  • 使用場景:適用于對文件進(jìn)行互斥訪問的場景,如進(jìn)程間共享的文件或資源。
  • 優(yōu)點(diǎn):簡單易用,可以保證共享文件的互斥訪問。
  • 缺點(diǎn):對文件操作需要顯式加鎖和解鎖,繁瑣且容易出錯。不適用于跨網(wǎng)絡(luò)的進(jìn)程通信。

綜上所述,不同的機(jī)制適用于不同的場景。選擇適當(dāng)?shù)倪M(jìn)程間同步機(jī)制取決于具體的需求和限制。信號量和共享內(nèi)存適用于高性能數(shù)據(jù)共享和同步,管道適用于具有父子關(guān)系的進(jìn)程通信,消息隊列適用于異步通信,文件鎖適用于文件的互斥訪問。文章來源地址http://www.zghlxwxcb.cn/news/detail-788401.html

到了這里,關(guān)于Linux和windows進(jìn)程同步與線程同步那些事兒(五):Linux下進(jìn)程同步的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

    Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

    ??進(jìn)程是一個動態(tài)過程,而非靜態(tài)文件,它是程序的一次運(yùn)行過程,當(dāng)應(yīng)用程序被加載到內(nèi)存中運(yùn)行之后它就稱為了一個進(jìn)程,當(dāng)程序運(yùn)行結(jié)束后也就意味著進(jìn)程終止,這就是進(jìn)程的一個生命周期。 ??Linux 系統(tǒng)下進(jìn)程通常存在 6 種不同的狀態(tài),分為:就緒態(tài)、運(yùn)行態(tài)、僵

    2023年04月24日
    瀏覽(24)
  • 逍遙自在學(xué)C語言 | 枚舉的那些事兒

    逍遙自在學(xué)C語言 | 枚舉的那些事兒

    在C語言中,枚舉是一種方便組織和表示一組相關(guān)常量的工具。枚舉類型有助于提高代碼的可讀性和可維護(hù)性。本文將介紹C語言枚舉的基本概念、語法和用法,以及一些高級技巧。 第一位閃亮登場,有請今后會一直教我們C語言的老師 —— 自在。 第二位上場的是和我們一起學(xué)

    2024年02月08日
    瀏覽(30)
  • Linux 線程和線程同步

    ?【操作系統(tǒng)】2.進(jìn)程和線程 - imXuan - 博客園 (cnblogs.com) 線程:light weight process(LWP)輕量級的進(jìn)程,在 Linux 中本質(zhì)上仍然是一個進(jìn)程 進(jìn)程:有獨(dú)立的地址空間,獨(dú)立PCB,可以當(dāng)作只有一個線程的進(jìn)程。進(jìn)程是計算機(jī) 資源分配的最小單位 線程:有獨(dú)立的PCB,共享物理地址空間

    2024年02月05日
    瀏覽(20)
  • 『Linux』第九講:Linux多線程詳解(三)_ 線程互斥 | 線程同步

    『Linux』第九講:Linux多線程詳解(三)_ 線程互斥 | 線程同步

    「前言」文章是關(guān)于Linux多線程方面的知識,上一篇是?Linux多線程詳解(二),今天這篇是 Linux多線程詳解(三),內(nèi)容大致是線程互斥與線程同步,講解下面開始! 「歸屬專欄」Linux系統(tǒng)編程 「主頁鏈接」個人主頁 「筆者」楓葉先生(fy) 「楓葉先生有點(diǎn)文青病」「每篇一句

    2024年02月02日
    瀏覽(23)
  • 【Linux】Linux線程互斥與同步

    【Linux】Linux線程互斥與同步

    臨界資源:多線程執(zhí)行流共享的資源就叫做臨界資源 臨界區(qū):每個線程內(nèi)部,訪問臨界資源的代碼,就叫做臨界區(qū) 互斥:任何時刻,互斥保證有且只有一個執(zhí)行流進(jìn)入臨界區(qū),訪問臨界資源,通常對臨界資源起保護(hù)作用 原子性:不會被任何調(diào)度機(jī)制打斷的操作,該操作只有

    2024年02月04日
    瀏覽(23)
  • Linux——線程3|線程互斥和同步

    Linux——線程3|線程互斥和同步

    我們上一篇提到過,多個線程執(zhí)行下面代碼可能會出錯,具體原因可查看上一篇Linux博客。 為避免這種錯誤的出現(xiàn),我們可采用加鎖保護(hù)。 PTHREAD_MUTEX_INITIALIZER 用pthread_mutex_t定義一把鎖。ptherad_mutex_init是對鎖進(jìn)行初始化的函數(shù)。如果這把鎖是全局的并且是靜態(tài)定義的,我們可

    2024年02月05日
    瀏覽(28)
  • Linux 多線程( 進(jìn)程VS線程 | 線程控制 )

    Linux 多線程( 進(jìn)程VS線程 | 線程控制 )

    進(jìn)程是資源分配的基本單位。 線程是OS調(diào)度的基本單位。 線程共享進(jìn)程數(shù)據(jù),但也擁有自己的一部分?jǐn)?shù)據(jù): 線程ID 一組寄存器 ,用來保存每個線程的上下文數(shù)據(jù),讓每個線程能夠合理調(diào)度。 棧 ,每個線程入棧出棧產(chǎn)生的臨時變量必須保存到每個線程的私有棧中,所以棧對于

    2024年02月07日
    瀏覽(15)
  • Linux--線程-條件控制實(shí)現(xiàn)線程的同步

    Linux--線程-條件控制實(shí)現(xiàn)線程的同步

    1.條件變量 條件變量是線程另一可用的同步機(jī)制。條件變量給多個線程提供了一個會合的場所。條件變量與互斥量一起使用時,允許線程以無競爭的方式等待特定的條件發(fā)生。 條件本身是由互斥量保護(hù)的。線程在改變條件狀態(tài)前必須首先鎖住互斥量,其他線程在獲得互斥量之

    2024年02月05日
    瀏覽(23)
  • Linux線程同步實(shí)例

    Linux線程同步實(shí)例

    生產(chǎn)者消費(fèi)者模型是一種常用的并發(fā)設(shè)計模式,它可以解決生產(chǎn)者和消費(fèi)者之間的速度不匹配、解耦、異步等問題。生產(chǎn)者消費(fèi)者模型的應(yīng)用場景有很多,例如Excutor任務(wù)執(zhí)行框架、消息中間件activeMQ、任務(wù)的處理時間比較長的情況下等。 生產(chǎn)者消費(fèi)者模型的基本結(jié)構(gòu)如下 :

    2024年02月07日
    瀏覽(20)
  • Linux->線程同步

    Linux->線程同步

    前言: 1 線程同步引入 2 條件變量 2.1 線程饑餓 2.2 條件變量接口 2.3 添加條件變量 3 生產(chǎn)者和消費(fèi)者模型 ? ? ? ? 本篇主要講解了關(guān)于線程同步的相關(guān)知識,還有生產(chǎn)者和消費(fèi)者模型的認(rèn)識和使用。 ? ? ? ? 在講解線程同步之前,我們先來看一下當(dāng)一個程序之中只有線程互

    2024年02月11日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包