C 多线程编程总结

C语言是一种非常流行的编程语言,被广泛应用于各种应用程序和系统开发。C语言支持多线程编程,多线程是同时执行的多个独立的线程,可以提高程序性能和并发处理能力。本文将介绍C语言多线程编程的基本概念、使用方法和实例说明。

一、多线程编程基本概念

1.线程概念

线程是操作系统调度的基本单位,是进程中的一个控制流程,说白了就是程序执行的一条路径。一个程序可以包含多个线程,它们可以同时或交替执行,共享相同的全局数据。

2.线程的优点

(1)提高程序并发处理能力,充分利用多核CPU的计算资源。

(2)增加程序的响应速度,提高用户体验。

(3)避免单线程程序的阻塞,提高程序的稳定性和可靠性。

(4)可以将复杂的任务拆分成多个小任务,并行执行,提高程序的执行效率。

3.线程创建和销毁

线程的创建和销毁是多线程编程的重要操作,可以通过函数pthread_create()和pthread_exit()实现。

pthread_create()函数的原型如下:

```c

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

```

参数说明:

- thread:指向新线程的指针。

- attr:指向线程属性结构体的指针,可以为NULL。

- start_routine:是新线程执行的函数,返回void *类型的指针,参数为void *类型的指针。

- arg:是传递给新线程的参数,可以为NULL。

pthread_exit()函数的原型如下:

```c

void pthread_exit(void *retval);

```

参数说明:

- retval:指定的线程退出状态。

二、多线程编程使用方法

1.头文件和链接库

多线程编程需要包含头文件pthread.h,并链接pthread库,可以使用编译选项"-pthread"或"-lpthread"来指定。

2.线程创建

在主线程中,通过调用pthread_create()函数创建新线程并执行指定的线程函数。

```c

#include

void *thread_func(void *arg)//线程函数

{

//do something

pthread_exit((void *) 0);

}

int main()

{

pthread_t tid; //线程ID

int ret; //返回值

ret = pthread_create(&tid, NULL, thread_func, NULL);//创建新线程

if (ret != 0) {

printf("pthread_create error.\n");

return -1;

}

//do something

pthread_exit((void *) 0); //主线程退出

return 0;

}

```

3.线程等待

在主线程中,可以通过调用pthread_join()函数等待子线程完成。

```c

#include

void *thread_func(void *arg)

{

//do something

pthread_exit((void *) 0);

}

int main()

{

pthread_t tid; //线程ID

int ret; //返回值

ret = pthread_create(&tid, NULL, thread_func, NULL);//创建新线程

if (ret != 0) {

printf("pthread_create error.\n");

return -1;

}

//等待子线程完成

ret = pthread_join(tid, NULL);

if (ret != 0) {

printf("pthread_join error.\n");

return -1;

}

//do something

pthread_exit((void *) 0); //主线程退出

return 0;

}

```

4.线程同步

多个线程同时访问同一个全局变量可能会出现数据竞争问题,需要使用线程同步技术来解决。

- 互斥锁

互斥锁用于对共享资源的互斥访问,通过pthread_mutex_init()函数初始化互斥锁,pthread_mutex_lock()函数加锁,pthread_mutex_unlock()函数解锁。

```c

#include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义静态初始化互斥锁

void *thread_func(void *arg)

{

//加锁

pthread_mutex_lock(&mutex);

//do something

//解锁

pthread_mutex_unlock(&mutex);

pthread_exit((void *) 0);

}

int main()

{

pthread_t tid; //线程ID

int ret; //返回值

ret = pthread_create(&tid, NULL, thread_func, NULL);//创建新线程

if (ret != 0) {

printf("pthread_create error.\n");

return -1;

}

pthread_mutex_lock(&mutex);//加锁

//do something

pthread_mutex_unlock(&mutex);//解锁

pthread_exit((void *) 0); //主线程退出

return 0;

}

```

- 条件变量

条件变量用于线程间的事件通知和等待,通过pthread_cond_init()函数初始化条件变量,pthread_cond_wait()函数等待条件变量,pthread_cond_signal()或pthread_cond_broadcast()函数唤醒等待线程。

```c

#include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义静态初始化互斥锁

pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //定义静态初始化条件变量

void *thread_func(void *arg)

{

pthread_mutex_lock(&mutex);//加锁

//等待条件变量

ret = pthread_cond_wait(&cond, &mutex);

if (ret != 0) {

printf("pthread_cond_wait error.\n");

return -1;

}

//do something

pthread_mutex_unlock(&mutex);//解锁

pthread_exit((void *) 0);

}

int main()

{

pthread_t tid; //线程ID

int ret; //返回值

ret = pthread_create(&tid, NULL, thread_func, NULL);//创建新线程

if (ret != 0) {

printf("pthread_create error.\n");

return -1;

}

pthread_mutex_lock(&mutex);//加锁

//设置条件变量

ret = pthread_cond_signal(&cond);

if (ret != 0) {

printf("pthread_cond_signal error.\n");

return -1;

}

pthread_mutex_unlock(&mutex);//解锁

pthread_exit((void *) 0); //主线程退出

return 0;

}

```

5.线程池

线程池是一种常见的多线程编程模型,可以提高程序执行效率和并发处理能力。

```c

#include

#include

#define MAX_THREADS 10 //最大线程数

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义静态初始化互斥锁

pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //定义静态初始化条件变量

int thread_count = 0; //线程数计数器

bool thread_func(void *arg)

{

//do something

return true;

}

void *thread_pool_func(void *arg)

{

while (true) {

pthread_mutex_lock(&mutex);//加锁

while (thread_count == 0) {

pthread_cond_wait(&cond, &mutex);//等待条件变量

}

thread_count--;

pthread_mutex_unlock(&mutex);//解锁

thread_func(arg);//线程函数

}

}

int main()

{

pthread_t tid[MAX_THREADS]; //线程ID数组

int i; //循环计数器

int ret; //返回值

for (i = 0; i < MAX_THREADS; i++) {

ret = pthread_create(&tid[i], NULL, thread_pool_func, NULL);//创建新线程

if (ret != 0) {

printf("pthread_create error.\n");

return -1;

}

}

//do something

pthread_mutex_lock(&mutex);//加锁

thread_count++;

pthread_cond_signal(&cond);//唤醒等待线程

pthread_mutex_unlock(&mutex);//解锁

return 0;

}

```

三、多线程编程实例说明

1.多线程并发服务器

```c

#include

#include

#include

#include

#include

#include

#define MAX_CLIENTS 10 //最大客户数

#define BUF_SIZE 1024 //缓冲区大小

int client_count = 0; //客户数计数器

int client_fds[MAX_CLIENTS]; //客户套接字数组

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义静态初始化互斥锁

void *client_func(void *arg)

{

int sockfd = *(int *)arg; //客户套接字

char buf[BUF_SIZE]; //缓冲区

int n;

while (true) {

n = read(sockfd, buf, BUF_SIZE);//读取客户数据

if (n <= 0) {

//客户已断开连接

pthread_mutex_lock(&mutex);//加锁

for (int i = 0; i < client_count; i++) {

if (client_fds[i] == sockfd) {

client_count--;

for (int j = i; j < client_count; j++) {

client_fds[j] = client_fds[j+1];

}

break;

}

}

pthread_mutex_unlock(&mutex);//解锁

close(sockfd);//关闭客户套接字

return NULL;

}

buf[n] = '\0';

printf("[Client %d]: %s", sockfd, buf);//在服务器打印出客户数据

//将数据广播给其他客户

pthread_mutex_lock(&mutex);//加锁

for (int i = 0; i < client_count; i++) {

if (client_fds[i] != sockfd) {

write(client_fds[i], buf, n);

}

}

pthread_mutex_unlock(&mutex);//解锁

memset(buf, 0, BUF_SIZE);

}

}

void *server_func(void *arg)

{

int sockfd = *(int *)arg; //服务器套接字

int connfd; //客户套接字

struct sockaddr_in client_addr; //客户地址

socklen_t client_len = sizeof(client_addr);

while (true) {

connfd = accept(sockfd, (struct sockaddr *) &client_addr, &client_len);//等待客户连接

if (connfd < 0) {

printf("accept error\n");

continue;

}

pthread_mutex_lock(&mutex);//加锁

if (client_count < MAX_CLIENTS) {

client_fds[client_count] = connfd;

client_count++;

pthread_t tid;

pthread_create(&tid, NULL, client_func, &connfd);//为客户创建新线程

printf("[Server]: Client %s:%d connected.\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));//在服务器打印客户连接信息

} else {

printf("too many clients\n");

close(connfd);//关闭客户套接字

}

pthread_mutex_unlock(&mutex);//解锁

}

}

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

{

int sockfd; //服务器套接字

struct sockaddr_in server_addr; //服务器地址

pthread_t tid;

//创建服务器套接字

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

printf("socket error\n");

return -1;

}

//绑定服务器地址

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(8888);

if (bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {

printf("bind error\n");

return -1;

}

//监听客户连接

if (listen(sockfd, 10) < 0) {

printf("listen error\n");

return -1;

}

//创建服务器线程

pthread_create(&tid, NULL, server_func, &sockfd);

//等待线程结束

pthread_join(tid, NULL);

//关闭套接字

close(sockfd);

return 0;

}

```

2.多线程图像处理

这个例子演示了如何使用多线程来加速图像处理,代码实现了双边滤波算法,可以处理RGB图像。

```c

#include

#include

#include

#include

#include

#include "bmpfile.h"

#define MAX_THREADS 10 //最大线程数

bmpfile_t *read_bmp(const char *filename);

int write_bmp(bmpfile_t *bmp, const char *filename);

void *thread_func(void *arg);

struct thread_data{

int start;

int end;

bmpfile_t *bmp_in;

bmpfile_t *bmp_out;

};

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

{

bmpfile_t *bmp_in, *bmp_out;

uint32_t width, height;

int threads, i, ret;

pthread_t tid[MAX_THREADS];

struct thread_data td[MAX_THREADS];

if (argc != 4) {

printf("Usage: bilateral_filter input.bmp output.bmp threads\n");

return -1;

}

bmp_in = read_bmp(argv[1]);//读取输入图像

if (bmp_in == NULL) {

printf("read bmp error\n");

return -1;

}

if (bmp_in->header.bitcount != 24) {

printf("only support 24-bit image\n");

bmp_destroy(bmp_in);

return -1;

}

width = bmp_in->header.width;

height = bmp_in->header.height;

bmp_out = bmp_create(width, height, bmp_in->header.bitcount);//创建输出图像

if (bmp_out == NULL) {

printf("bmp create error\n");

bmp_destroy(bmp_in);

return -1;

}

threads = atoi(argv[3]);//获取线程数

if (threads <= 0 || threads > MAX_THREADS) {

threads = 1;

}

for (i = 0; i < threads; i++) {

td[i].start = (i * height) / threads;

td[i].end = ((i + 1) * height) / threads - 1;

td[i].bmp_in = bmp_in;

td[i].bmp_out = bmp_out;

ret = pthread_create(&tid[i], NULL, thread_func, &td[i]);//为每个线程创建任务

if (ret != 0) {

printf("pthread_create error.\n");

}

}

for (i = 0; i < threads; i++) {

pthread_join(tid[i], NULL);//等待所有线程完成任务

}

write_bmp(bmp_out, argv[2]);//保存输出图像

bmp_destroy(bmp_in);

bmp_destroy(bmp_out);

return 0;

}

bmpfile_t *read_bmp(const char *filename)

{

bmpfile_t *bmp = NULL;

FILE *f = fopen(filename, "rb");

if (f != NULL) {

bmp = bmp_create_32(0,0,0);

bmp_read(bmp, f);

fclose(f);

}

return bmp;

}

int write_bmp(bmpfile_t *bmp, const char *filename)

{

if (bmp == NULL || filename == NULL) {

return -1;

}

FILE *f = fopen(filename, "wb");

if (f != NULL) {

bmp_write(bmp, f);

fclose(f);

return 0;

}

return -1;

}

void *thread_func(void *arg)

{

int x, y, i, j, k, r, g, b;

double w, dw, weight, dist, r_sum, g_sum, b_sum, weight_sum;

bmpfile_t *bmp_in, *bmp_out;

struct thread_data *td = (struct thread_data *)arg;

uint32_t width = td->bmp_in->header.width;

uint32_t height = td->end - td->start + 1;

uint8_t *p_in = td->bmp_in->data + td->start * td->bmp_in->header.pitch;

uint8_t *p_out = td->bmp_out->data + td->start * td->bmp_out->header.pitch;

for (y = td->start; y <= td->end; y++) {

for (x = 0; x < width; x++) {

r_sum = 0.0; g_sum = 0.0; b_sum = 0.0; weight_sum = 0.0;//初始化

for (i = -2; i <= 2; i++) {

for (j = -2; j <= 2; j++) {

if (y + i >= 0 && y + i < height && x + j >= 0 && x + j < width) {

r = p_in[(y 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.37seo.cn/

点赞(39) 打赏

评论列表 共有 1 条评论

冬天的雪花 1年前 回复TA

走该走的路,见想见的人。

立即
投稿
发表
评论
返回
顶部