#include <string.h> #include <math.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <linux/soundcard.h> int init_mixer("/dev/mixer", int *fd) { if ((*fd = open(device_name, O_WRONLY)) < 0){ fprintf(stderr, "Error opening %s: %s\n", device_name, strerror(errno)); return -1; } return 0; } int contrl_vol(int *fd, int increment) { int vol; ioctl(*fd,MIXER_READ(SOUND_MIXER_VOLUME),&vol); vol += increment; ioctl(*fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol); return 0; }
CU首页 >> 读书频道 >> 分类浏览 >> Linux环境C程序设计 >> 阅读内容
Linux环境C程序设计
16.3 媒体播放器——完善退出和音量控制功能
一些小型的应用程序很少使用进程间通信机制,但在Linux系统中,可利用D-Bus获取操作系统的变化。例如在桌面环境退出时,D-Bus将发出相关信号告知接入系统总线的程序,使这些程序能够在强制退出前保存数据。除此以外,音量调节、网络连接、新的文件系统被挂载(CDROM、USB驱动器)都可由D-Bus报告。这是因为Linux的多种桌面环境均使用D-Bus,应用程序的可移植性也得到了保证。本节将介绍媒体播放器使用D-Bus的实例。
16.3.1 媒体播放器在桌面环境退出时响应
媒体播放器需要使用图形界面,而图形界面必须依赖于一种Linux桌面环境。Linux的内核与桌面环境是分离的,在系统退出前首先会结束桌面会话,因此可通过D-Bus获得桌面环境退出的消息。媒体播放器退出前需要进行一系统工作,例如保存当前程序界面的数据、保存播放列表等,这些工作在核心控制模块收到GENERAL_EXIT指令后进行。使用D-Bus需启动GLib主循环,相关代码可放在主函数或某个独立的函数内,代码如下:
#include <glib.h> // 包含glib库
#include <dbus/dbus-glib.h> // 包含glib库中D-Bus管理库
int link_dbus()
{
GMainLoop *loop; // 定一个事件循环对象的指针
DBusConnection *bus; // 定义总线连接对象的指针
DBusError error; // 定义D-Bus错误消息对象
loop = g_main_loop_new(NULL, FALSE); // 创建新事件循环对象
dbus_error_init(&error); // 将错误消息对象连接到D-Bus错误消息对象
bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error); // 连接到系统总线
if (!bus) { // 判断是否连接错误
g_warning("连接到D-Bus失败: %s", error.message);
// 使用GLib输出错误警告信息
dbus_error_free(&error); // 清除错误消息
return 1;
}
dbus_connection_setup_with_g_main(bus, NULL);// 将总线设为接收GLib事件
// 循环
dbus_bus_add_match(bus, "type='signal',interface='com.system.dbus.Signal'"); // 定义匹配器
dbus_connection_add_filter(bus, general_exit, loop, NULL);
// 调用函数接收消息
g_main_loop_run(loop); // 启动事件循环
return 0;
}
该函数连接到D-Bus的系统总线中,并接收com.system.dbus.Signal管道内的信息,系统关闭信息即通过该管道传送。当接收到任何消息后,将调用general_exit()函数进行处理,代码如下:
static DBusHandlerResult // 定义接收消息函数的细节
general_exit (DBusConnection *connection, DBusMessage *message, void*user_data)
{
GMainLoop *loop = user_data; // 定义事件循环对象的指针,并与主函数中
// 的同步
if (dbus_message_is_signal // 接收连接成功消息,判断是否连接失败
(message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) {
g_main_loop_quit (loop); // 退出主循环
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus_message_is_signal(message, "com.burtonini.dbus.Signal", "Ping")) {
// 指定消息对象路径,判断是否成功
DBusError error; // 定义错误对象
char *s;
dbus_error_init(&error); // 将错误消息对象连接到D-Bus错误消息
// 对象
if (dbus_message_get_args // 接收消息,并判断是否有错误
(message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) {
if (!strcmp(s, "SHUTDOWN")) { // 判断收到的消息是否为系统关闭信息
main_core(GENERAL_EXIT, NULL); // 调用核心控制模块
dbus_free (s); // 清除该消息
&n
linux中两种基本的同步方法是信号量和互斥量。这两种方法很相似,而且它们可以相互通过对方来实现。
信号量概述
下面介绍用信号量进行同步。
信号量概念由荷兰科学家Dijkstra首先提出。信号量是一个特殊类型的变量,它可以被增加或者减少。但对其的关键访问被保证是原子操作,即使在一个多线程程序中也是如此。
信号量有两种类型:
(1)二进制信号量。它只有0和1两种取值。
(2)计数信号量。它可以有更大的取值范围。
如果要用信号量来保护一段代码,使其每次只能被一个执行线程运行,就要用到二进制信号量、。
如果要允许有限数目的线程执行一段指定的代码,就需要用到计数信号量。
由于计数信号量并不常用,而且它实际上仅仅是二进制信号量的一种扩展,这里之介绍二进制信号量。
信号量的相关函数
信号量函数的名字都以sem_开头。线程中使用的基本函数有4个。
注意,需要包含头文件:
#include<semaphore.h>
(1)创建信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);函数解释:
sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。
如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。(因为通过 fork(2) 创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。)所有可以访问共享内存区域的进程都可以勇冠 sem_post(3)、sem_wait(3) 等等操作信号量。初始化一个已经初始的信号量其结果未定义。
返回值
sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。
错误
EINVAL
value 超过 SEM_VALUE_MAX。
ENOSYS
pshared 非零,但系统还没有支持进程共享的信号量。
下面是控制信号量的两个函数:
(2)信号量减一操作
int sem_wait(sem_t * sem);函数说明
sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,这信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就 会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加 一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
返回值
所有这些函数在成功时都返回 0;错误保持信号量值没有更改,-1 被返回,并设置 errno 来指明错误。
错误
EINTR
这个调用被信号处理器中断,
EINVAL
sem 不是一个有效的信号量。
(3)信号量加一操作
int sem_post(sem_t * sem);说明
sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同 时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。
返回值
sem_post() 成功时返回 0;错误时,信号量的值没有更改,-1 被返回,并设置 errno 来指明错误。
错误
EINVAL
sem 不是一个有效的信号量。
EOVERFLOW
信号量允许的最大值将要被超过。
(4)清理信号量
int sem_destroy (sem_t *sem);这个函数也使用一个信号量指针做参数,归还自己战胜的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。
与其它的函数一样,这些函数在成功时都返回“0”。
信号量的使用
下面主线程中创建了一个新线程,用来统计输入的字符串中字符的个数。信号量用来控制两个线程对存储字符串数组的访问。
代码:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <semaphore.h> //线程函数 void *thread_function(void *arg); sem_t bin_sem;//信号量对象 #define WORK_SIZE 1024 char work_area[WORK_SIZE];//工作区 int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&bin_sem,0,0);//初始化信号量对象 if(res)//初始化信号量失败 { perror("Semaphore initialization failed\n"); exit(EXIT_FAILURE); } //创建新线程 res = pthread_create(&a_thread,NULL,thread_function,NULL); if(res) { perror("Thread creation failed\n"); exit(EXIT_FAILURE); } printf("Input some text.Enter 'end' to finish\n"); while(strncmp("end",work_area,3) != 0) {//输入没有结束 fgets(work_area,WORK_SIZE,stdin); sem_post(&bin_sem);//给信号量值加一 } printf("waiting for thread to finish\n"); //等待子线程结束,收集子线程信息 res = pthread_join(a_thread,&thread_result); if(res) { perror("Thread join failed\n"); exit(EXIT_FAILURE); } printf("Thread joined\n"); //销毁信号量对象 sem_destroy(&bin_sem); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sem_wait(&bin_sem);//将信号量值减一。 while(strncmp("end",work_area,3)) { printf("You input %d characters\n",strlen(work_area) - 1); sem_wait(&bin_sem); } pthread_exit(NULL);//线程终止执行 }
运行结果:
问题描述:严重: Servlet /图书馆管理系统 threw load() exception
java.lang.ClassNotFoundException: org.apache.struts.action.ActionServlet
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:532)
at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:514)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:133)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1137)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1081)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5027)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1114)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1673)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
2013-1-5 10:18:03 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-apr-8082"]
2013-1-5 10:18:03 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-apr-8009"]
2013-1-5 10:18:03 org.apache.catalina.startup.Catalina start
信息: Server startup in 3027 ms
解决方法:我在Myeclipse9.0的tomcat损坏,重新装过tomcat7.0,先检查配置,没有错,后按照网上其他人说法,检查jar包(antlr.jarcommons-beanutils.jar commons-digester.jar commons-logging.jar commons-fileupload.jar commons-validator.jar jakarta-oro.jarstruts.jar),不是因为包的问题,最后,把tomcat目录:C:\Program
Files\Apache Software Foundation\Tomcat 7.0\webapps中原先的项目删掉即可。