代码演示:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
// 读取键盘输入的线程函数
void *keyboardThread(void *arg) {
char c;
while (1) {
// 从键盘读取一个字符
c = getchar();
// 打印从键盘读取的字符
printf("键盘输入: %c\n", c);
}
}
int main(){
int ret = -1;
int fd = -1;
char buf[200];
pthread_t th =-1;
//k开一个子线程
ret = pthread_create(&th,NULL,keyboardThread,NULL);
//主进程读取鼠标输入
memset(buf,0,sizeof(buf));
//读取鼠标
fd = open("/dev/input/mouse0",O_RDONLY);
if(fd<0){
perror("open:");
return -1;
}
while(1){
read (fd,buf,2); //从鼠标读取两位
printf("mouse读出来的内容是 :【%s】\n",buf);
}
return 0;
}
效果如下:
需要注意到的一点是:
使用了pthread库,因此编译时需要链接 -lpthread
并发执行: 线程使得程序可以同时执行多个任务,从而提高了系统的并发性。这允许程序在某个线程等待I/O操作完成的同时,其他线程可以继续执行,提高了系统的利用率。
资源共享: 线程之间共享同一进程的地址空间,可以更方便地共享数据。这样,多个线程可以访问和修改相同的变量,共享同一份代码和静态数据,减少了资源的冗余使用。
轻量级: 相较于进程,线程是轻量级的执行单元。线程的创建、销毁和切换成本较低,因此在需要频繁创建和销毁执行单元的场景中,线程更为适用。
响应性: 多线程可以使程序更加响应用户输入和事件。例如,在图形用户界面(GUI)应用程序中,一个线程可以负责用户界面的更新,而另一个线程可以处理用户输入,使得应用程序看起来更为流畅。
模块化设计: 通过将不同的任务分配给不同的线程,可以实现模块化的程序设计。每个线程负责一个特定的功能或任务,使得代码更易于理解、维护和扩展。
性能提升: 在多核处理器上,多线程程序可以更好地利用硬件资源,从而提高程序的性能。并行执行的线程可以在多个核心上同时运行,加速任务的完成。
异步编程: 线程可以用于实现异步编程模型,通过在后台执行任务,使得程序能够继续执行其他操作。这对于需要处理I/O操作或等待外部事件的场景非常有用。
实时性: 一些实时系统需要在特定时间内完成任务,线程可以用于实现对任务的及时响应,确保实时性要求得到满足。
pthread_create
POSIX 线程库中用于创建新线程的函数。该函数的原型如下:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);
thread:一个指向 pthread_t 类型的变量的指针,用于存储新线程的标识符。
attr:一个指向 pthread_attr_t 类型的变量的指针,用于设置新线程的属性,通常可以传入 NULL 以使用默认属性。
start_routine:是一个指向函数的指针,该函数定义了新线程的起始点。新线程将从这个函数开始执行。这个函数的签名应为 void* start_routine(void*)。
arg:是传递给 start_routine 函数的参数。
函数返回值为 0 表示成功创建新线程,非零值表示出现了错误。
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
可以说 pthread_create 与 pthread_join 成对出现的,一个负责创建一个负责回收
代码演示:
#include <stdio.h>
#include <pthread.h>
void *printMessage(void *arg) {
char *message = (char *)arg;
printf("%s\n", message);
pthread_exit((void *)42);
}
int main() {
pthread_t tid;
char *message = "Hello from the new thread!";
void *result;
// 创建新线程
int result_create = pthread_create(&tid, NULL, printMessage, (void *)message);
if (result_create != 0) {
fprintf(stderr, "Thread creation failed: %d\n", result_create);
return 1;
}
// 等待新线程结束
int result_join = pthread_join(tid, &result);
if (result_join != 0) {
fprintf(stderr, "Thread join failed: %d\n", result_join);
return 1;
}
// 打印新线程的返回值
printf("New thread returned: %ld\n", (long)result);
return 0;
}
int pthread_detach(pthread_t thread);
这个函数的参数 thread 是要分离的线程的标识符,通常由 pthread_create 返回得到。函数返回值为 0 表示成功,非零值表示出现了错误。
调用 pthread_detach 将线程标记为“分离状态”,这意味着线程结束后,系统会自动回收其资源。分离状态的线程不再需要主线程调用 pthread_join 来等待其结束,因为线程结束后,它的所有资源都会被自动回收。
一旦调用 pthread_detach 将线程标记为分离状态,就无法再将其改回非分离状态。这意味着在设置分离状态后,主线程无需显式等待该线程的结束。
代码演示:
#include <stdio.h>
#include <pthread.h>
void *printMessage(void *arg) {
char *message = (char *)arg;
printf("%s\n", message);
pthread_exit(NULL);
}
int main() {
pthread_t tid;
char *message = "Hello from the detached thread!";
// 创建新线程并设置为分离状态
int result_create = pthread_create(&tid, NULL, printMessage, (void *)message);
if (result_create != 0) {
fprintf(stderr, "Thread creation failed: %d\n", result_create);
return 1;
}
// 设置线程为分离状态
int result_detach = pthread_detach(tid);
if (result_detach != 0) {
fprintf(stderr, "Thread detach failed: %d\n", result_detach);
return 1;
}
// 主线程继续执行,不需要等待新线程结束
return 0;
}
int pthread_cancel(pthread_t thread);
函数返回值为 0 表示成功发送取消请求,非零值表示出现了错误。
线程会在取消点检查取消请求。取消点是一些标准的库函数,例如 pthread_join、sleep 等。
线程在执行这些函数时,会检查是否有取消请求。
代码演示:
#include <stdio.h>
#include <pthread.h>
void *cancelExample(void *arg) {
while (1) {
printf("Thread is running...\n");
sleep(1); // 休眠是一个取消点
}
pthread_exit(NULL);
}
int main() {
pthread_t tid;
// 创建新线程
int result_create = pthread_create(&tid, NULL, cancelExample, NULL);
if (result_create != 0) {
fprintf(stderr, "Thread creation failed: %d\n", result_create);
return 1;
}
// 主线程休眠一段时间后发送取消请求
sleep(3);
int result_cancel = pthread_cancel(tid);
if (result_cancel != 0) {
fprintf(stderr, "Thread cancel failed: %d\n", result_cancel);
return 1;
}
// 主线程等待新线程结束
pthread_join(tid, NULL);
return 0;
}
void pthread_exit(void *retval);
pthread_exit 是一个线程库提供的函数,用于终止当前线程的执行。它可以传递一个指针作为线程的返回值,这个指针将被用作线程的退出状态。当调用 pthread_exit 时,线程的资源(如栈空间)不会被回收,需要通过其他线程调用 pthread_join 来等待并回收这个线程的资源。
void pthread_cleanup_push(void (*routine)(void *), void *arg);
pthread_cleanup_push 将清理函数和参数推入线程的清理处理栈。在线程退出时,栈上的所有清理函数都会被依次执行。
代码演示:
#include <stdio.h>
#include <pthread.h>
void cleanupHandler(void *arg) {
printf("Cleanup handler: %s\n", (char *)arg);
}
void *threadFunction(void *arg) {
// 推入清理函数和参数到栈
pthread_cleanup_push(cleanupHandler, "First cleanup");
pthread_cleanup_push(cleanupHandler, "Second cleanup");
// 线程的主要逻辑
printf("Thread is running.\n");
// 模拟线程取消点(Cancellation Point)
sleep(2);
// 弹出清理函数,但不执行
pthread_cleanup_pop(0);
// 弹出清理函数,并执行
pthread_cleanup_pop(1);
// 正常退出
pthread_exit(NULL);
}
int main() {
pthread_t tid;
// 创建新线程
int result_create = pthread_create(&tid, NULL, threadFunction, NULL);
if (result_create != 0) {
fprintf(stderr, "Thread creation failed: %d\n", result_create);
return 1;
}
// 等待线程结束
pthread_join(tid, NULL);
return 0;
}
使用 pthread_self 函数来获取当前线程的线程标识符(Thread ID)。该函数的原型如下:
pthread_t pthread_self(void);
调用该函数就会返回调用线程的线程标识符