C语言中的并发编程

并发编程,在C语言中既可以基于进程,也可以基于IO多路复用,还可以基于多线程实现并发。
进程是运行的程序,是操作系统资源分配的单位,线程是操作系统调度的单位,进程之间通信必须使用显式的IPC(进程间通信)机制。线程之间通信的方式则有很多

相关库函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// #include <unistd.h>
// 创建一个进程
pid_t fork(void);
// 获取调用该函数进程标识符
pid_t getpid(void);
// #include <pthread.h>
// @see: https://man7.org/linux/man-pages/man3/pthread_create.3.html
int pthread_create(
pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void *),
void *restrict arg
);

// #include <sys/select.h>
// @see: https://man7.org/linux/man-pages/man2/select.2.html
int select(
int nfds,
fd_set *restrict readfds,
fd_set *restrict writefds,
fd_set *restrict exceptfds,
struct timeval *restrict timeout
);

void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

// #include <semaphore.h>
// @see https://man7.org/linux/man-pages/man3/sem_init.3.html
int sem_init(
sem_t *sem,
int pshared,
unsigned int value
);
int sem_post(sem_t *sem);
int sem_wait(sem_t *sem);


// #include <sys/time.h>
int setitimer(
int which,
const struct itimerval *restrict value,
struct itimerval *restrict ovalue
);

多进程

多线程

IO多路复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXLINE 255

int open_fd(in_port_t port) {
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
int fd = socket(AF_INET, SOCK_STREAM, 0);
int err = bind(fd, (struct sockaddr *)&address, sizeof(address));
if (err == -1) {
printf("[%s] - (%s:%d) error bind %d", __FILE__, __FUNCTION__ , __LINE__, port);
exit(0);
}
return fd;
}

void command() {
char buf[MAXLINE];
if (!fgets(buf, MAXLINE, stdin)) {
exit(0);
}
printf("%s", buf);
}

void echo(int conn) {
char buf[MAXLINE];
ssize_t len = recv(conn, buf, sizeof(buf), 0);
buf[len] = '\0';
fprintf(stdout, "%s", buf);
send(conn, buf, sizeof(buf), 0);
}

int main(int argc, char **argv) {
int listenfd, connfd;
socklen_t client_len;
struct sockaddr_storage client_addr;
fd_set read_set, ready_set;
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(0);
}

listenfd = open_fd(atoi(argv[1]));
FD_ZERO(&read_set);
FD_SET(STDIN_FILENO, &read_set);
FD_SET(listenfd, &read_set);

while (1) {
ready_set = read_set;
select(listenfd + 1, &ready_set, NULL, NULL, NULL);
if (FD_ISSET(STDIN_FILENO, &ready_set)) {
command();
}

if (FD_ISSET(listenfd, &ready_set)) {
client_len = sizeof(struct sockaddr_storage);
connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_len);
echo(connfd);
close(listenfd);
}
}

return 0;
}