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/
走该走的路,见想见的人。