`
forfuture1978
  • 浏览: 412574 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

高级Linux程序设计第五章:进程间通信

阅读更多
  • 五种进程间通信的方式:

    • 共享内存(shared memory):其允许多个进程通过读写同一块内存地址来相互通信。

    • 内存映射(Mapped memory):其和共享内存相似,然而它是和文件系统上的一个文件相关联的。

    • 管道(Pipe):其允许一个进程到另一个相关进程的顺序通信。

    • 先入先出队列(FIFO):和管道类似,然而因为其对应于文件系统上的文件名,可以在两个不相关的进程间通信。

    • Socket:其允许在不同的计算机上的不同进程间通信。

1、共享内存(Shared Memory)

  • 共享内存时进程间通信方式中最快的一种,因为进程是共享同一块内存。

  • 内核并不提供对共享内存访问的同步机制,因而必须自己提供同步方式。

  • 要用共享内存块,需要一个进程首先分配此内存块。

  • 欲访问共享内存块的进程必须要连接到此内存块。

  • 在使用完共享内存块的时候,进程必须要卸载此内存块。

  • 需要有一个进程释放此内存块。

  • 所有的共享内存块都是以4KB的整数倍分配。

 

1.1、分配

  • 进程用函数shmget分配一个共享内存块。

    • 第一个参数是共享内存块的key

      • 不同的进程可以根据此key来访问同一个共享内存块。

      • 使用IPC_PRIVATE作为key会保证创建一个新的共享内存块。

      • 如果多个进程访问同一个共享内存块,则必须用同一个key。

    • 第二个参数表示内存块的大小。

    • 第三个参数是一系列标志位:

      • IPC_CREAT创建一个新的内存块。

      • IPC_EXCL此标志位和IPC_CREAT一起使用。如果key已经存在,则此标志位使得shmget失败。

1.2、连接(Attachment )和卸载(Detachment)

  • 一个进程需要调用shmat来连接一个共享内存。

    • 第一个参数是共享内存块的id,由shmget返回。

    • 第二个参数是一个指针,其指向共享内存块映射的内存地址,如果是NULL,则系统会自动选择一个可用的内存地址。

    • 第三个参数是标志位:

      • SHM_RND表示第二个参数所指定的地址必须同页的大小对齐。

      • SHM_RDONLY表示此内存块只读。

    • 此函数返回值是连接的共享内存的起始地址。

  • 共享内存块可用函数shmdt卸载,应传给它共享内存块的起始地址。

  • 调用exit及exec函数自动卸载共享内存块。

 

1.3、控制和释放共享内存块

  • shmctl函数可用返回和修改共享内存块的信息。

    • 第一个参数是共享内存块id

    • 欲得到一个共享内存块的信息,第二个参数设为IPC_STAT,第三个参数是指向shmid_ds结构体的指针。

    • 欲删除一个共享内存块,第二个参数设为IPC_RMID,第三个参数设为NULL。

  • 一个共享内存块在使用结束后,必须用shmctl显式的释放。

  • 调用exit和exec自动卸载共享内存块,但是不释放。

#include <stdio.h>

#include <sys/shm.h>

#include <sys/stat.h>

int main ()

{

    int segment_id;

    char* shared_memory;

    struct shmid_ds shmbuffer;

    int segment_size;

    const int shared_segment_size = 0x6400;

    /* Allocate a shared memory segment. */

    segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);

    /* Attach the shared memory segment. */

    shared_memory = (char*) shmat (segment_id, 0, 0);

    printf (“shared memory attached at address %p\n”, shared_memory);

    /* Determine the segment’s size. */

    shmctl (segment_id, IPC_STAT, &shmbuffer);

    segment_size = shmbuffer.shm_segsz;

    printf (“segment size: %d\n”, segment_size);

    /* Write a string to the shared memory segment. */

    sprintf (shared_memory, “Hello, world.”);

    /* Detach the shared memory segment. */

    shmdt (shared_memory);

    /* Reattach the shared memory segment, at a different address. */

    shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);

    printf (“shared memory reattached at address %p\n”, shared_memory);

    /* Print out the string from shared memory. */

    printf (“%s\n”, shared_memory);

    /* Detach the shared memory segment. */

    shmdt (shared_memory);

    /* Deallocate the shared memory segment. */

    shmctl (segment_id, IPC_RMID, 0);

    return 0;

 

ipcs命令可用查看进程间通信机制的信息

使用-m可查看共享内存的信息

% ipcs -m

------ Shared Memory Segments --------

key shmid owner perms bytes nattch status

0x00000000 1627649 user 640 25600 0

ipcrm命令可删除进程间通信对象.

% ipcrm shm 1627649

[liuchao@localhost ~]$ ipcs

------ Shared Memory Segments --------

key shmid owner perms bytes nattch status

0x00000000 196608 liuchao 600 393216 2 dest

0x764867bd 65537 liuchao 600 1 0

0x2c0056d5 98306 liuchao 600 1 0

0x500e7827 131075 liuchao 600 1 0

0x20e0f21d 163844 liuchao 600 1 0

0x00000000 229381 liuchao 600 393216 2 dest

0x00000000 262150 liuchao 600 393216 2 dest

0x00000000 294919 liuchao 600 393216 2 dest

0x00000000 327688 liuchao 600 393216 2 dest

0x00000000 360457 liuchao 600 393216 2 dest

0x00000000 393226 liuchao 600 393216 2 dest

0x00000000 425995 liuchao 600 393216 2 dest

0x00000000 458764 liuchao 600 393216 2 dest

0x00000000 491533 liuchao 600 393216 2 dest

0x00000000 557070 liuchao 600 393216 2 dest

0x00000000 589839 liuchao 600 393216 2 dest

------ Semaphore Arrays --------

key semid owner perms nsems

0x59d9bc4a 0 liuchao 600 1

0x3bd464f2 32769 liuchao 600 1

------ Message Queues --------

key msqid owner perms used-bytes messages

 

2、进程信号量

2.1、分配(Allocation)和释放(Deallocation)

  • 调用semget分配一个信号量,调用semctl来释放一个信号量。

  • semget的参数为一个信号量集的key,信号量集中的信号量的个数,权限标志位,返回值为信号量集id。

  • semctl的参数为信号量集的id,信号量集中的信号量的个数,IPC_RMID。

  • 当所有的使用信号量的进程结束后,信号量仍然存在。

  • 最后一个使用信号量集的进程必须显式的删除它。

#include <sys/ipc.h>

#include <sys/sem.h>

#include <sys/types.h>

/* We must define union semun ourselves. */

union semun {

    int val;

    struct semid_ds *buf;

    unsigned short int *array;

    struct seminfo *__buf;

};

/* Obtain a binary semaphore’s ID, allocating if necessary. */

int binary_semaphore_allocation (key_t key, int sem_flags)

{

    return semget (key, 1, sem_flags);

}

/* Deallocate a binary semaphore. All users must have finished their

use. Returns -1 on failure. */

int binary_semaphore_deallocate (int semid)

{

    union semun ignored_argument;

    return semctl (semid, 1, IPC_RMID, ignored_argument);

}

2.2、初始化信号量

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

/* We must define union semun ourselves. */

union semun {

    int val;

    struct semid_ds *buf;

    unsigned short int *array;

    struct seminfo *__buf;

};

/* Initialize a binary semaphore with a value of 1. */

int binary_semaphore_initialize (int semid)

{

    union semun argument;

    unsigned short values[1];

    values[0] = 1;

    argument.array = values;

    return semctl (semid, 0, SETALL, argument);

}

 

2.3、Wait和Post操作

  • semop函数支持wait和post操作。

    • 第一个参数是信号量集id。

    • 第二个参数是一个sembuf结构体的数组。

    • 第三个参数是数组的长度。

  • sembuf结构体:

    • sem_num是信号量集中作为操作对象的信号量的号。

    • sem_op表示对信号量的操作。如果sem_op是正数,则其将被加到信号量的值上。如果sem_op是负数,则得到其绝对值,如果此值能够使得信号量的值为负,则阻塞当前线程,直到此信号量的值等于sem_op的绝对值。如果sem_op为零,阻塞当前线程,直到信号量的值为零。

    • sem_flg是标志位,IPC_NOWAIT使得此操作不会被阻塞,SEM_UNDO表示当进程结束的时候,系统自动取消此次操作。

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

/* Wait on a binary semaphore. Block until the semaphore value is positive, then

decrement it by 1. */

int binary_semaphore_wait (int semid)

{

    struct sembuf operations[1];

    /* Use the first (and only) semaphore. */

    operations[0].sem_num = 0;

    /* Decrement by 1. */

    operations[0].sem_op = -1;

    /* Permit undo’ing. */

    operations[0].sem_flg = SEM_UNDO;

    return semop (semid, operations, 1);

}

/* Post to a binary semaphore: increment its value by 1.

This returns immediately. */

int binary_semaphore_post (int semid)

{

    struct sembuf operations[1];

    /* Use the first (and only) semaphore. */

    operations[0].sem_num = 0;

    /* Increment by 1. */

    operations[0].sem_op = 1;

    /* Permit undo’ing. */

    operations[0].sem_flg = SEM_UNDO;

    return semop (semid, operations, 1);

}

 

3、内存映射(Mapped Memory)

3.1、映射一个普通文件

  • 使用mmap函数可将一个普通文件映射到进程内存中。

    • 第一个参数是文件将映射到的内存地址,NULL使得Linux自动选择一个可用的地址。

    • 第二个参数是映射的长度。

    • 第三个参数是映射的内存的保护模式:PROT_READ,PROT_WRITE,PROT_EXEC。

    • 第四个参数是一个标志位:

      • MAP_FIXED表示映射的内存地址必须和页对齐。

      • MAP_PRIVATE表示写入映射的内存的数据不会写入关联的文件,而是写入另一个文件副本,对其他线程不可见。

      • MAP_SHARED表示写入映射的内存的数据会立即写入关联的文件,不会有缓存。

    • 第五个参数是关联文件的文件描述符。

    • 第六个参数是映射的文件的偏移量。

(mmap-write.c) Write a Random Number to a Memory-Mapped File

#include <stdlib.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <time.h>

#include <unistd.h>

#define FILE_LENGTH 0x100

/* Return a uniformly random number in the range [low,high]. */

int random_range (unsigned const low, unsigned const high)

{

    unsigned const range = high - low + 1;

    return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));

}

int main (int argc, char* const argv[])

{

    int fd;

    void* file_memory;

    /* Seed the random number generator. */

    srand (time (NULL));

    /* Prepare a file large enough to hold an unsigned integer. */

    fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    lseek (fd, FILE_LENGTH+1, SEEK_SET);

    write (fd, “”, 1);

    lseek (fd, 0, SEEK_SET);

    /* Create the memory mapping. */

    file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);

    close (fd);

    /* Write a random integer to memory-mapped area. */

    sprintf((char*) file_memory, “%d\n”, random_range (-100, 100));

    /* Release the memory (unnecessary because the program exits). */

    munmap (file_memory, FILE_LENGTH);

    return 0;

}

(mmap-read.c) Read an Integer from a Memory-Mapped File, and Double It

#include <stdlib.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <unistd.h>

#define FILE_LENGTH 0x100

int main (int argc, char* const argv[])

{

    int fd;

    void* file_memory;

    int integer;

    /* Open the file. */

    fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);

    /* Create the memory mapping. */

    file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    close (fd);

    /* Read the integer, print it out, and double it. */

    sscanf (file_memory, “%d”, &integer);

    printf (“value: %d\n”, integer);

    sprintf ((char*) file_memory, “%d\n”, 2 * integer);

    /* Release the memory (unnecessary because the program exits). */

    munmap (file_memory, FILE_LENGTH);

    return 0;

}

3.2、共同访问一个文件

  • 不同的进程可以通过将同一个文件映射到内存来通信。

  • 设置MAP_SHARD使得写入到映射的内存的数据会立即写入关联的文件,并对另一个文件可见。

  • 如果不做以上设定,则Linux会对数据进行缓存,可以用函数msync将缓存写入文件。

    • 前两个参数表示映射的内存块。

    • 第三个参数是标志位:

      • MS_ASTYNC:写缓存并不立即执行。

      • MS_SYNC:写缓存立即执行。

      • MS_INVALIDATE:所有的文件映射都被刷新,可以看到最新的更新。

msync (mem_addr, mem_length, MS_SYNC | MS_INVALIDATE);

  • 设置MAP_PRIVATE将创建一个写即复制的映射区。写入这些映射区的数据仅仅在当前进程可见,对其他进程不可见。

4、管道(Pipes)

4.1、创建管道

int pipe_fds[2];

int read_fd;

int write_fd;

pipe (pipe_fds);

read_fd = pipe_fds[0];

write_fd = pipe_fds[1];

4.2、用管道来进行子进程和父进程之间的通信

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

/* Write COUNT copies of MESSAGE to STREAM, pausing for a second between each. */

void writer (const char* message, int count, FILE* stream)

{

    for (; count > 0; --count) {

        /* Write the message to the stream, and send it off immediately. */

        fprintf (stream, “%s\n”, message);

        fflush (stream);

        /* Snooze a while. */

        sleep (1);

    }

}

/* Read random strings from the stream as long as possible. */

void reader (FILE* stream)

{

    char buffer[1024];

    /* Read until we hit the end of the stream. fgets reads until either a newline or the end-of-file. */

    while (!feof (stream) && !ferror (stream) && fgets (buffer, sizeof (buffer), stream) != NULL)

        fputs (buffer, stdout);

}

int main ()

{

    int fds[2];

    pid_t pid;

    /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */

    pipe (fds);

    /* Fork a child process. */

    pid = fork ();

    if (pid == (pid_t) 0) {

        FILE* stream;

        /* This is the child process. Close our copy of the write end of the file descriptor. */

        close (fds[1]);

        /* Convert the read file descriptor to a FILE object, and read from it. */

        stream = fdopen (fds[0], “r”);

        reader (stream);

        close (fds[0]);

    }

    else {

        /* This is the parent process. */

        FILE* stream;

        /* Close our copy of the read end of the file descriptor. */

        close (fds[0]);

        /* Convert the write file descriptor to a FILE object, and write to it. */

        stream = fdopen (fds[1], “w”);

        writer (“Hello, world.”, 5, stream);

        close (fds[1]);

    }

    return 0;

}

4.3、用管道重定向标准输入,标准输出,错误流。

#include <stdio.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

int main ()

{

    int fds[2];

    pid_t pid;

    /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */

    pipe (fds);

    /* Fork a child process. */

    pid = fork ();

    if (pid == (pid_t) 0) {

        /* This is the child process. Close our copy of the write end of the file descriptor. */

        close (fds[1]);

        /* Connect the read end of the pipe to standard input. */

        dup2 (fds[0], STDIN_FILENO);

        /* Replace the child process with the “sort” program. */

        execlp (“sort”, “sort”, 0);

    }

    else {

        /* This is the parent process. */

        FILE* stream;

        /* Close our copy of the read end of the file descriptor. */

        close (fds[0]);

        /* Convert the write file descriptor to a FILE object, and write to it. */

        stream = fdopen (fds[1], “w”);

        fprintf (stream, “This is a test.\n”);

        fprintf (stream, “Hello, world.\n”);

        fprintf (stream, “My dog has fleas.\n”);

        fprintf (stream, “This program is great.\n”);

        fprintf (stream, “One fish, two fish.\n”);

        fflush (stream);

        close (fds[1]);

        /* Wait for the child process to finish. */

        waitpid (pid, NULL, 0);

   }

   return 0;

}

4.4、打开(popen)和关闭(pclose)管道

#include <stdio.h>

#include <unistd.h>

int main ()

{

    FILE* stream = popen (“sort”, “w”);

    fprintf (stream, “This is a test.\n”);

    fprintf (stream, “Hello, world.\n”);

    fprintf (stream, “My dog has fleas.\n”);

    fprintf (stream, “This program is great.\n”);

    fprintf (stream, “One fish, two fish.\n”);

    return pclose (stream);

}

4.5、先进先出队列(FIFOs)

  • 一个先进先出队列是一个管道,只不过在文件系统中有文件名与之对应。

  • FIFOs又被称为命名管道。

  • mkfifo命令可以创建一个FIFO

 

% mkfifo /tmp/fifo

% ls -l /tmp/fifo

prw-rw-rw- 1 samuel users 0 Jan 16 14:04 /tmp/fifo

  • mkfifo函数可以创建一个FIFO

  • 第一个参数是文件系统中的路径。

  • 第二个参数是权限。

  • 访问FIFO和访问一个普通文件相同。

  • 如果两个进程通过FIFO进行通信,则需要一个进程打开一个FIFO用于写,另一个进程打开同一个FIFO用于读。

5、套接字(Sockets)

  • 创建一个套接字:

    • 命名空间:PF_LOCAL和PF_UNIX表示本地命名空间,PF_INET表示互联网命名空间。

    • 通信方式:SOCK_STREAM表示面向连接的套接字,SOCK_DGRAM表示面向数据报的套接字。

  • 关闭套接字:close

  • 连接套接字:欲在客户端和服务器段建立连接,客户端调用connect,指向服务器的地址,服务器端等待accept连接。

  • 绑定套接字:bind,将套接字绑定到一个地址。

  • 监听套接字:listen,使得服务器监听一个端口,等待accept一个连接。

  • 接受套接字:accept,接受一个来自客户端的连接。

 

5.1、本地命名空间套接字

访问同一台机器的套接字可以使用本地命名空间:PF_LOCAL和PF_UNIX

(socket-server.c) Local Namespace Socket Server

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <unistd.h>

/* Read text from the socket and print it out. Continue until the

socket closes. Return nonzero if the client sent a “quit”

message, zero otherwise. */

int server (int client_socket)

{

    while (1) {

        int length;

        char* text;

        /* First, read the length of the text message from the socket. If read returns zero, the client closed the connection. */

        if (read (client_socket, &length, sizeof (length)) == 0)

            return 0;

        /* Allocate a buffer to hold the text. */

        text = (char*) malloc (length);

        /* Read the text itself, and print it. */

        read (client_socket, text, length);

        printf (“%s\n”, text);

        /* Free the buffer. */

        free (text);

        /* If the client sent the message “quit,” we’re all done. */

        if (!strcmp (text, “quit”))

            return 1;

    }

}

int main (int argc, char* const argv[])

{

    const char* const socket_name = argv[1];

    int socket_fd;

    struct sockaddr_un name;

    int client_sent_quit_message;

    /* Create the socket. */

    socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);

    /* Indicate that this is a server. */

    name.sun_family = AF_LOCAL;

    strcpy (name.sun_path, socket_name);

    bind (socket_fd, &name, SUN_LEN (&name));

    /* Listen for connections. */

    listen (socket_fd, 5);

    /* Repeatedly accept connections, spinning off one server() to deal with each client. Continue until a client sends a “quit” message. */

    do {

        struct sockaddr_un client_name;

        socklen_t client_name_len;

        int client_socket_fd;

        /* Accept a connection. */

        client_socket_fd = accept (socket_fd, &client_name, &client_name_len);

        /* Handle the connection. */

        client_sent_quit_message = server (client_socket_fd);

        /* Close our end of the connection. */

        close (client_socket_fd);

    } while (!client_sent_quit_message);

    /* Remove the socket file. */

    close (socket_fd);

    unlink (socket_name);

    return 0;

}

(socket-client.c) Local Namespace Socket Client

#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <unistd.h>

/* Write TEXT to the socket given by file descriptor SOCKET_FD. */

void write_text (int socket_fd, const char* text)

{

    /* Write the number of bytes in the string, including NUL-termination. */

    int length = strlen (text) + 1;

    write (socket_fd, &length, sizeof (length));

    /* Write the string. */

    write (socket_fd, text, length);

}

int main (int argc, char* const argv[])

{

    const char* const socket_name = argv[1];

    const char* const message = argv[2];

    int socket_fd;

    struct sockaddr_un name;

    /* Create the socket. */

    socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);

    /* Store the server’s name in the socket address. */

    name.sun_family = AF_LOCAL;

    strcpy (name.sun_path, socket_name);

    /* Connect the socket. */

    connect (socket_fd, &name, SUN_LEN (&name));

    /* Write the text on the command line to the socket. */

    write_text (socket_fd, message);

    close (socket_fd);

    return 0;

}

 

5.2、互联网套接字

(socket-inet.c) Read from a WWW Server

#include <stdlib.h>

#include <stdio.h>

#include <netinet/in.h>

#include <netdb.h>

#include <sys/socket.h>

#include <unistd.h>

#include <string.h>

/* Print the contents of the home page for the server’s socket. Return an indication of success. */

void get_home_page (int socket_fd)

{

    char buffer[10000];

    ssize_t number_characters_read;

    /* Send the HTTP GET command for the home page. */

    sprintf (buffer, “GET /\n”);

    write (socket_fd, buffer, strlen (buffer));

    /* Read from the socket. The call to read may not

    return all the data at one time, so keep trying until we run out. */

    while (1) {

        number_characters_read = read (socket_fd, buffer, 10000);

        if (number_characters_read == 0)

            return;

        /* Write the data to standard output. */

        fwrite (buffer, sizeof (char), number_characters_read, stdout);

    }

}

int main (int argc, char* const argv[])

{

    int socket_fd;

    struct sockaddr_in name;

    struct hostent* hostinfo;

    /* Create the socket. */

    socket_fd = socket (PF_INET, SOCK_STREAM, 0);

    /* Store the server’s name in the socket address. */

    name.sin_family = AF_INET;

    /* Convert from strings to numbers. */

    hostinfo = gethostbyname (argv[1]);

    if (hostinfo == NULL)

        return 1;

    else

        name.sin_addr = *((struct in_addr *) hostinfo->h_addr);

    /* Web servers use port 80. */

    name.sin_port = htons (80);

    /* Connect to the Web server */

    if (connect (socket_fd, &name, sizeof (struct sockaddr_in)) == -1) {

        perror (“connect”);

        return 1;

    }

    /* Retrieve the server’s home page. */

    get_home_page (socket_fd);

    return 0;

}

3
3
分享到:
评论

相关推荐

    Linux程序设计参考书-六部

    ioctl第6章Linux进程间通信第7章声音编程第8章字符单元图形第9章I/O端口编程第10章把应用程序移植到Linux上附录以字母顺序排列的系统调用第四部Linux内核概念系统结构第1章系统结构第2章子系统的系统结构第3章结论...

    Linux程序设计中文第4版.part2

    已经整理好目录,需要下载3个包,因为只能上传50M,...第13章 进程间通信:管道 第14章 信号量、共享内存和消息队列 第15章 套接字 第16章 用GTK+进行GNOME编程 第17章 用Qt进行KDE编程 第18章 Linux标准33

    Linux程序设计中文第4版.part3

    已经整理好目录,需要下载3个包,因为只能上传50M,...第13章 进程间通信:管道 第14章 信号量、共享内存和消息队列 第15章 套接字 第16章 用GTK+进行GNOME编程 第17章 用Qt进行KDE编程 第18章 Linux标准33

    Linux程序设计中文第4版.part1

    已经整理好目录,需要下载3个包,因为只能上传50M,所以...第13章 进程间通信:管道 第14章 信号量、共享内存和消息队列 第15章 套接字 第16章 用GTK+进行GNOME编程 第17章 用Qt进行KDE编程 第18章 Linux标准33

    Linux程序设计 第4版.haozip01

    第13章 进程间通信:管道 443 13.1 什么是管道 443 13.2 进程管道 444 13.3 将输出送往popen 445 13.3.1 传递更多的数据 446 13.3.2 如何实现popen 447 13.4 pipe调用 449 13.5 父进程和子进程 451 13.5.1 ...

    Linux C程序设计大全

    第14章 进程间通信 第15章 线程 第4篇 Linux文件操作 第17章 文件I/O 第18章 文件管理 第19章 目录操作 第20章 特殊文件 第21章 基于流的I/O 第5篇 Linux网络编程 第22章 TCP和UDP协议 第23章 网络编程基础 第24章 ...

    Linux程序设计 第4版.haozip02

    第13章 进程间通信:管道 443 13.1 什么是管道 443 13.2 进程管道 444 13.3 将输出送往popen 445 13.3.1 传递更多的数据 446 13.3.2 如何实现popen 447 13.4 pipe调用 449 13.5 父进程和子进程 451 13.5.1 ...

    嵌入式Linux程序设计案例与实验教程(配套光盘)第一部分

    2.4 进程创建以及进程间通信25 2.4.1 进程概述25 2.4.2 进程的相关函数25 2.4.3 信号概述27 2.4.4 信号的相关函数27 2.4.5 管道概述27 2.4.6 管道的相关函数28 实验2.4 进程相关的应用程序设计28 综合实验一...

    嵌入式Linux程序设计案例与实验教程(配套光盘)第二部分

    2.4 进程创建以及进程间通信25 2.4.1 进程概述25 2.4.2 进程的相关函数25 2.4.3 信号概述27 2.4.4 信号的相关函数27 2.4.5 管道概述27 2.4.6 管道的相关函数28 实验2.4 进程相关的应用程序设计28 综合实验一...

    嵌入式Linux程序设计案例与实验教程(配套光盘)第三部分

    2.4 进程创建以及进程间通信25 2.4.1 进程概述25 2.4.2 进程的相关函数25 2.4.3 信号概述27 2.4.4 信号的相关函数27 2.4.5 管道概述27 2.4.6 管道的相关函数28 实验2.4 进程相关的应用程序设计28 综合实验一...

    Linux的内核与编程

    本书结合源代码分析了Linux操作系统,结合源代码是本书的一个亮点本书共有两个大部分:内核原理和编程方法共19章: 第1章 软件基础 (介绍了内核的数据结构) 第2章 内存管理 (各种管理算法) 第3章 进程第4章 进程间通信...

    Unix系统编程(程序设计语言+系统调用)

    本课程主要讲述在Unix/Linux环境下高级编程的方法,其内容包括文件、信号、POSIX线程、UDP、WEB和客户机服务器等...第五章 进程间通信 第六章 管道 第七章 高级进程间通信 第八章 精灵进程 目前有八章PPT,之后持续更新

    嵌入式Linux程序设计案例与实验教程-实例代码

    2.4 进程创建以及进程间通信25 2.4.1 进程概述25 2.4.2 进程的相关函数25 2.4.3 信号概述27 2.4.4 信号的相关函数27 2.4.5 管道概述27 2.4.6 管道的相关函数28 实验2.4 进程相关的应用程序设计28 ...

    精通LINUX下的C编程(配套光盘)第一部分

    第6章 进程间通信(IPC) 6.1 进程间通信机制概述 6.2 信号处理 6.3 管道 6.4 System V IPC机制 6.5 小结 习题 第7章 线程操作 7.1 线程概述 7.2 线程管理 7.3 小结 习题 第8章 网络编程 8.1 概述 8.2 ...

    史上最强的嵌入式底层驱动开发课程 Linux系统开发+Linux高级程序+主板开发+ARM等

    │ ├53 - Linux高级程序_进程间通信_Semaphore1.mp4 │ ├54 - Linux高级程序_进程间通信_Semaphore2.avi │ ├55 - 线程_Thread1.avi │ ├56 - 线程_Thread2.mp4 │ ├57 - 线程_Thread3.mp4 │ ├58 - 网络编程_...

    嵌入式Linux应用程序开发标准教程(第2版全)

    接着系统地讲解了嵌入式Linux的环境搭建,以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及嵌入式图形界面的开发等,并且还安排了丰富...

    嵌入式Linux ARM开发课件第五讲

    ARM7~ARM9体系结构体系结构介绍 ARM7(9)TDMI处理器内核...进程间通信: 进程通信的基本概念,管道、信号、消息队列、信号量、共享内存。 网络通讯接口,socket通信编程。 串口通讯程序和编程实践 多线程程序设计 等。

    嵌入式Linux应用程序开发教程PPT.zip

    第1章 Linux快速入门 第2章 Linux基础命令 第3章 Linux下C编程基础 第4章 嵌入式系统基础 ...第8章 进程间通信 第9章 多线程编程 第10章 嵌入式Linux网络编程 第11章 嵌入式Linux设备驱动开发 第12章 Qt图形编程基础

    边干边学——LINUX内核指导

    第5章 系统调用 5. 1 一个简单的例子 5. 2 系统调用基础知识 5. 3 相关数据结构. 源代码分析及流程 5. 4 详细讲解一个系统调用的实现 5. 5 简单系统调用的添加 5. 6 较高级主题:添加一个更复杂的系统调用 第6章 共享...

Global site tag (gtag.js) - Google Analytics