1. 线程编程概述
线程(Thread)是多任务处理中的一种实现模式。在Unix/Linux环境中,线程被视为轻量级的进程,它们共享相同的地址空间,允许程序中的不同部分同时执行。线程编程是一种高效的并发编程方式,它可以让程序员在单个进程中实现并发操作,提高程序的执行效率。
线程和进程的联系和区别:
线程和进程都是计算机科学中描述程序执行过程的基本概念,但它们在资源使用、执行过程和错误处理等方面存在明显的差异。
- 资源使用:进程是操作系统资源分配的基本单位,它拥有独立的代码和数据空间(即程序上下文)。然而,同一类线程共享进程所拥有的全部资源,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间的切换开销相对较小。
- 执行过程:进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位。每个进程都有自己的地址空间,至少有5种基本状态,它们是:初始态、执行态、等待状态、就绪状态和终止状态。然而,线程是CPU调度和分派的基本单位,线程必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
- 错误处理:当一个进程崩溃时,它对其他进程不会产生影响。然而,一个线程崩溃后整个进程都会死掉,因为线程是进程的一部分。所以,多进程比多线程更健壮。
总的来说,进程和线程在资源使用、执行过程和错误处理等方面存在明显差异。进程拥有独立的资源,而线程则共享资源。此外,进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。在错误处理方面,进程比线程更健壮。
线程编程的基本概念包括线程创建、线程终止、线程同步、线程通信等。下面我们将从这几个方面来详细介绍线程编程
。
2. 线程创建
在Unix/Linux环境中,创建线程的函数是pthread_create。该函数需要传入以下参数:
- thread:指向线程标识符的指针。
- attr:指向线程属性的指针,通常设置为NULL。
- start_routine:指向线程函数的指针。
- arg:传递给线程函数的参数。
以下是pthread_create函数的示例代码:
- #include <pthread.h>
-
- void* my_thread_func(void* arg) {
- // 线程函数代码
- return NULL;
- }
-
- int main() {
- pthread_t my_thread;
- int ret = pthread_create(&my_thread, NULL, my_thread_func, NULL);
- if (ret != 0) {
- // 线程创建失败
- return -1;
- }
- // 等待线程结束
- pthread_join(my_thread, NULL);
- return 0;
- }
复制代码在上面的代码中,我们定义了一个名为my_thread_func的线程函数,并在main函数中通过pthread_create函数创建了一个名为my_thread的新线程来执行该函数。如果线程创建成功,pthread_create函数将返回0,否则返回错误码。最后,我们使用pthread_join函数等待my_thread线程结束。
3. 线程终止
在Unix/Linux环境中,终止线程的函数是pthread_exit。该函数需要传入一个指向void的指针,该指针将被用作线程的返回值。如果主线程中调用了pthread_join函数来等待子线程结束,那么该指针将被传递给pthread_join函数。以下是一个使用pthread_exit函数的示例代码: - #include <pthread.h>
-
- void* my_thread_func(void* arg) {
- // 线程函数代码
- pthread_exit(NULL); // 终止线程并返回NULL
- }
-
- int main() {
- pthread_t my_thread;
- int ret = pthread_create(&my_thread, NULL, my_thread_func, NULL);
- if (ret != 0) {
- // 线程创建失败
- return -1;
- }
- // 等待线程结束
- pthread_join(my_thread, NULL);
- return 0;
- }
复制代码
4. 线程同步
在多线程编程中,线程同步是一种关键技术,它用于协调多个线程的执行顺序,以避免资源竞争和数据不一致的问题。在Unix/Linux环境中,我们可以使用以下线程同步技术:
4.1 互斥锁(Mutex)
互斥锁是一种最基本的线程同步机制,它可以保证在任意时刻,只有一个线程可以访问共享资源。在Unix/Linux中,我们可以使用pthread库提供的函数来创建和管理互斥锁。
以下是使用互斥锁的示例代码: - #include <pthread.h>
-
- pthread_mutex_t mutex;
- int shared_data = 0;
-
- void* thread_func(void* arg) {
- pthread_mutex_lock(&mutex); // 加锁
- shared_data += 1;
- printf("Thread %ld: shared_data = %d\n", pthread_self(), shared_data);
- pthread_mutex_unlock(&mutex); // 解锁
- return NULL;
- }
-
- int main() {
- pthread_t thread1, thread2;
- pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
- pthread_create(&thread1, NULL, thread_func, NULL);
- pthread_create(&thread2, NULL, thread_func, NULL);
- pthread_join(thread1, NULL);
- pthread_join(thread2, NULL);
- pthread_mutex_destroy(&mutex); // 销毁互斥锁
- return 0;
- }
复制代码4.2 条件变量(Condition Variables)
条件变量是一种更高级的线程同步机制,它允许线程等待某个条件成立。当条件成立时,被阻塞的线程将被唤醒。在Unix/Linux中,我们可以使用pthread库提供的函数来创建和管理条件变量。
以下是使用条件变量的示例代码 :
- #include <pthread.h>
-
- pthread_cond_t cond;
- int shared_data = 0;
-
- void* thread_func(void* arg) {
- printf("Thread %ld: waiting for shared data...\n", pthread_self());
- pthread_cond_wait(&cond, &mutex); // 等待条件成立
- shared_data += 1;
- printf("Thread %ld: shared_data = %d\n", pthread_self(), shared_data);
- return NULL;
- }
-
- int main() {
- pthread_t thread1, thread2;
- pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
- pthread_cond_init(&cond, NULL); // 初始化条件变量
- pthread_create(&thread1, NULL, thread_func, NULL);
- pthread_create(&thread2, NULL, thread_func, NULL);
- pthread_join(thread1, NULL);
- pthread_join(thread2, NULL);
- pthread_mutex_destroy(&mutex); // 销毁互斥锁
- pthread_cond_destroy(&cond); // 销毁条件变量
- return 0;
- }
复制代码
5. 线程通信
在多线程编程中,线程之间的通信是一个常见的问题。在Unix/Linux环境中,我们可以使用以下线程通信技术:
5.1 管道(Pipe)
管道是一种最简单的线程通信方式,它允许一个线程向另一个线程发送数据。在Unix/Linux中,我们可以使用pipe函数来创建一个管道,并使用write函数向管道写入数据,使用read函数从管道读取数据。
以下是使用管道的示例代码: - #include <stdio.h>
- #include <unistd.h>
-
- int main() {
- int pipefd[2];
- pid_t pid;
- char buf[1024];
-
- if (pipe(pipefd) == -1) {
- perror("pipe");
- return -1;
- }
- pid = fork();
- if (pid == -1) {
- perror("fork");
- return -1;
- } else if (pid == 0) { // 子进程
- close(pipefd[1]); // 关闭管道的写端
- read(pipefd[0], buf, sizeof(buf));
- printf("Child process received message: %s\n", buf);
- close(pipefd[0]);
- } else { // 父进程
- close(pipefd[0]); // 关闭管道的读端
- write(pipefd[1], "Hello from parent", 17);
- close(pipefd[1]);
- }
- return 0;
- }
复制代码
5.2 消息队列(Message Queue)
消息队列是一种更高级的线程通信方式,它允许一个线程向另一个线程发送消息。在Unix/Linux中,我们可以使用msgget函数创建一个消息队列,并使用msgsnd函数向消息队列发送消息,使用msgrcv函数从消息队列接收消息。
以下是使用消息队列的示例代码: - #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
-
- #define MSG_SIZE 1024
-
- struct {
- long mtype;
- char mtext[MSG_SIZE];
- } msgbuf;
-
- int main() {
- int msqid;
- key_t key;
- char* mtext = "Hello from parent";
- int mtextlen = strlen(mtext);
-
- key = ftok(".", 'R'); // 获取消息队列的key值
- msqid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列
- if (msqid == -1) {
- perror("msgget");
- return -1;
- }
- msgbuf.mtype = mtextlen; // 设置消息类型为长度
- strncpy(msgbuf.mtext, mtext, mtextlen); // 设置消息内容为mtext字符串
- if (msgsnd(msqid, &msgbuf, mtextlen + sizeof(long), 0) == -1) { // 发送消息到消息队列中
- perror("msgsnd");
- return -1;
- } else { // 从消息队列接收消息并打印出来
- if (msgrcv(msqid, &msgbuf, MSG_SIZE, mtextlen, 0) == -1) {
- perror("msgrcv");
- return -1; else printf("Received message: %s\n", msgbuf.mtext); close(msqid); } } }
复制代码
|