exit()函数_complete函数

c74dc8d61a76f3b550d064e4428f16f1.png

上次讲解了一下add_wait_queue和add_wait_queue_exclusive两个函数,今天来讲另一个函数complete函数。

文件包含:

#include<linux/completion.h>

这个函数也是与内核进程调度相关的一个函数,因此它也位于kernel/sched/目录下,具体的实现在completion.c中,我们可以看看它的具体实现,这样对于我们更好的理解它的工作原理会很有帮助。

void complete(struct completion *x)
{
	unsigned long flags;

	spin_lock_irqsave(&x->wait.lock, flags);
	x->done++;
	__wake_up_locked(&x->wait, TASK_NORMAL, 1);
	spin_unlock_irqrestore(&x->wait.lock, flags);
}

我们可以看到,事实上complete函数调用了__wake_up_locked函数,只是在调用时采用了自旋锁并且关闭了中断。

函数功能:

complete函数用于唤醒等待队列中的睡眠进程,并记录等待队列中的唤醒次数,保存在字段done中。函数的参数是completion的一个结构体。

struct completion {
	unsigned int done;
	wait_queue_head_t wait;
};

completion结构体除了done字段之外,就是一个wait_queue_head_t的等待队列头。需要注意的是能唤醒的进程状态只能是TASK_INTERRUPTIBLE或者TASK_UNINTERRUPTIBLE,并且唤醒进程不是同步的,就是说只能唤醒一个然后再去唤醒另一个。

实例解析:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/sched.h>
#include<linux/wait.h>
#include<linux/completion.h>
#include<linux/kthread.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("viz.xu, xujiweigo@163.com");

static struct completion comple;
static struct task_struct* old_task;

int my_test_function(void* args)
{
	printk("enter kernel function!n");
	printk("the current pid is %dn",current->pid);
	printk("the value of done of the comple:%dn",comple.done);
	printk("the state of the init thread is %ldn",old_task->state);
	
	complete(&comple);

	printk("the value of done of the comple:%dn",comple.done);
	printk("the state of the init thread is %ldn",old_task->state);

return 0;
}

int __init complete_init(void)
{
	printk("complete init! current->pid = %dn",current->pid);

	struct task_struct* new_task = NULL;

	old_task = current;
	
	new_task = kthread_create_on_node(my_test_function,NULL,-1,"comple");

	init_completion(&comple);

	wait_queue_entry_t data;
	init_waitqueue_entry(&data,current);	

	wake_up_process(new_task);

	add_wait_queue(&(comple.wait),&data);
	
	long left_time = schedule_timeout_uninterruptible(1000);

	printk("the pid of new_task is %dn",new_task->pid);

	printk("the return result of the schedule_timeout_uninterruptible is %dn",left_time);

return 0;
}

void __exit complete_exit(void)
{
	printk("complete exit!n");
return;
}

module_init(complete_init);
module_exit(complete_exit);

结果分析:

[ 2814.212263] complete init! current->pid = 40020
[ 2814.212397] enter kernel function!
[ 2814.212399] the current pid is 40021
[ 2814.212400] the value of done of the comple:0
[ 2814.212401] the state of the init thread is 2
[ 2814.212403] the value of done of the comple:1
[ 2814.212404] the state of the init thread is 0
[ 2814.212406] the pid of new_task is 40021
[ 2814.212407] the return result of the schedule_timeout_uninterruptible is 1000

从结果可以看出,子进程和父进程都执行了,并且子进程在父进程之前执行完毕。在my_test_ function中调用complete函数,父进程的状态发生了改变2->0,这是因为我们在init函数中调用了schedule_timeout_uninterruptible,使得父进程处于TASK_UNINTERRUPTIBLE状态。同是,调用complete函数之后,comple的done字段变为1,说明参数在等待队列被唤醒了一次。

要在 C 语言中调用 SQL 函数进行查询,需要使用 SQL API。这里介绍一种常用的方法:使用 ODBC API。 ODBC(Open Database Connectivity)是一种通用的数据库访问标准,用于连接不同的数据库系统。使用 ODBC API 可以在 C 语言中访问各种数据库,包括 SQL Server、Oracle、MySQL 等。 以下是一个简单的示例代码,演示如何使用 ODBC API 连接数据库,执行查询语句并获取结果: ```c #include <stdio.h> #include <stdlib.h> #include <sql.h> #include <sqlext.h> int main() { SQLHENV env; SQLHDBC dbc; SQLHSTMT stmt; SQLRETURN ret; // 初始化环境句柄 ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to allocate environment handle\n"); exit(1); } // 设置环境属性 ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to set environment attribute\n"); exit(1); } // 分配连接句柄 ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to allocate connection handle\n"); exit(1); } // 连接数据库 SQLCHAR* conn_str = "DRIVER={MySQL ODBC 8.0 Unicode Driver};SERVER=localhost;DATABASE=test;UID=root;PWD=password;"; ret = SQLDriverConnect(dbc, NULL, conn_str, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to connect to database\n"); exit(1); } // 分配语句句柄 ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to allocate statement handle\n"); exit(1); } // 执行查询语句 ret = SQLExecDirect(stmt, "SELECT * FROM users", SQL_NTS); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to execute query\n"); exit(1); } // 获取结果集 SQLLEN num_cols; ret = SQLNumResultCols(stmt, &num_cols); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to get number of columns\n"); exit(1); } // 输出结果 SQLCHAR col_name[256]; SQLLEN col_name_len; SQLCHAR col_value[256]; SQLLEN col_value_len; while (SQLFetch(stmt) == SQL_SUCCESS) { for (int i = 1; i <= num_cols; i++) { ret = SQLDescribeCol(stmt, i, col_name, sizeof(col_name), &col_name_len, NULL, NULL, NULL, NULL); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to get column name\n"); exit(1); } ret = SQLGetData(stmt, i, SQL_C_CHAR, col_value, sizeof(col_value), &col_value_len); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { printf("Failed to get column value\n"); exit(1); } printf("%s: %s\n", col_name, col_value); } printf("\n"); } // 释放资源 SQLFreeHandle(SQL_HANDLE_STMT, stmt); SQLDisconnect(dbc); SQLFreeHandle(SQL_HANDLE_DBC, dbc); SQLFreeHandle(SQL_HANDLE_ENV, env); return 0; } ``` 这个示例代码连接的是 MySQL 数据库,需要安装 MySQL ODBC 驱动程序。在执行代码前,需要根据实际情况修改连接字符串。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值