Linux 线程的调度策略与优先级

调度策略有3种:

  1. SCHED_OTHER: 分时调度策略。线程的默认策略。此策略不能设置线程优先级。
  2. SCHED_FIFO: 实时调度策略,先到先服务。一旦线程占用cpu则一直运行。直到有更高优先级任务到达或自己放弃。此策略可设置线程优先级。
  3. SCHED_RR: 实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。保证了所有具有相同优先级的RR任务的调度公平此策略可设置线程优先级。

这3个宏在 sched.h 中定义。

线程优先级:

不同操作系统的优先级范围是不相同的,所以在设置线程优先级的时候需要先使用下面2个函数来查询其最大值和最小值:

int sched_get_priority_max(int policy); 
int sched_get_priority_min(int policy); 

参数policy是上面介绍的调度策略中的SCHED_FILOSCHED_RR,注意不能是SCHED_OTHER,因为SCHED_OTHER不支持优先级。

查询和设置调度策略:

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *param);

查询和设置线程优先级:

查询:

struct sched_param param; 
//首先查询线程的调度策略,赋给param
//参数attr是create线程时所使用的线程属性
pthread_attr_getschedparam(attr, ¶m); 
//从sched_param结构中获取线程优先级
param.__sched_priority; 

设置:

pthread_attr attr;
struct sched_param param;
//为param设置优先级10,这个值的范围由查询系统获得
param.__sched_priority = 10;
//参数attr是create线程时所使用的线程属性
pthread_attr_setschedparam(attr, ¶m);

ubuntu使用Fn调节屏幕亮度

OS: ubuntu 12.04

NVIDIA: 319.37

笔记本在ubuntu下更新了NVIDIA显卡驱动后,Fn快捷键调节屏幕亮度的功能失效了,可以使用下面的方法重新启用: 在 /etc/X11/xorg.conf的”Device”段加入一行:

    Option   "RegistryDwords" "EnableBrightnessControl=1"

现在xorg.conf看起来可能是这样:

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
    Option   "RegistryDwords" "EnableBrightnessControl=1"
EndSection

ubuntu安装BCM4313无线驱动

OS : ubuntu 12.04

sudo apt-get install --reinstall linux-headers-generic linux-headers-`uname -r`
sudo apt-get install --reinstall bcmwl-kernel-source
sudo modprobe wl

MediaPlayer 处理网络音频文件

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/TV01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Status :" />

    <TextView
        android:id="@+id/statusTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Unknown" />

    <TextView
        android:id="@+id/bufferPercentTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Buffer Percentage : " />

    <ProgressBar
        android:id="@+id/bufferSB"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:max="100" />

    <Button
        android:id="@+id/startBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start" />

    <Button
        android:id="@+id/stopBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop" />

</LinearLayout>

main_activity.java

public class MainActivity extends Activity implements OnCompletionListener,
		OnBufferingUpdateListener, OnClickListener, OnPreparedListener,
		OnErrorListener {

	Button startBtn;
	Button stopBtn;
	TextView statusTV;
	ProgressBar bufferSB;
	MediaPlayer mediaPlayer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		startBtn = (Button) findViewById(R.id.startBtn);
		startBtn.setOnClickListener(this);
		startBtn.setEnabled(false);

		stopBtn = (Button) findViewById(R.id.stopBtn);
		stopBtn.setOnClickListener(this);
		stopBtn.setEnabled(false);

		statusTV = (TextView) findViewById(R.id.statusTV);
		statusTV.setText("Creating mediaPlayer");

		bufferSB = (ProgressBar) findViewById(R.id.bufferSB);

		mediaPlayer = new MediaPlayer();
		mediaPlayer.setOnCompletionListener(this);
		mediaPlayer.setOnBufferingUpdateListener(this);
		mediaPlayer.setOnPreparedListener(this);
		mediaPlayer.setOnErrorListener(this);

		statusTV.setText("Created mediaPlayer");

		statusTV.setText("seting DataSource");
		try {
			mediaPlayer.setDataSource("http://lnmcc.net/wordpress/wp-content/uploads/2013/10/Rolling-In-The-Deep.mp3");
			statusTV.setText("setted DataSource");

			statusTV.setText("calling prepareAsync");
			// 不同于prepare(), prepareAsync()会立即返回,后台开始缓冲
			mediaPlayer.prepareAsync();
		} catch (IOException e) {
			Log.v("mediaPlayer.setDataSource", e.getMessage());
		}
	}

	@Override
	public void onClick(View v) {

		if (v == startBtn) {
			mediaPlayer.start();
			statusTV.setText("start play");

			startBtn.setEnabled(false);
			stopBtn.setEnabled(true);
		} else if (v == stopBtn) {
			mediaPlayer.pause();
			statusTV.setText("pause play");

			stopBtn.setEnabled(false);
			startBtn.setEnabled(true);
		}
	}

	@Override
	public boolean onError(MediaPlayer mp, int what, int extra) {

		statusTV.setText("invoke onError");

		switch (what) {
		case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
			statusTV.setText("MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK" + extra);
			break;
		case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
			statusTV.setText("MEDIA_ERROR_SERVER_DIED" + extra);
			break;
		case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
			statusTV.setText("MEDIA_ERROR_UNSUPPORTED" + extra);
			break;
		case MediaPlayer.MEDIA_ERROR_UNKNOWN:
			statusTV.setText("MEDIA_ERROR_UNKNOWN" + extra);
			break;
		}
		return false;
	}

	@Override
	public void onCompletion(MediaPlayer mp) {

		statusTV.setText("invoke onCompletion");
		stopBtn.setEnabled(false);
		startBtn.setEnabled(true);
	}

	@Override
	// 当后台缓冲数据发生变化时,会调用这个方法
	public void onBufferingUpdate(MediaPlayer mp, int percent) {
		bufferSB.setProgress(percent);
	}
	
	@Override
	//数据缓冲完成,可以播放
	public void onPrepared(MediaPlayer mp) {
		
		statusTV.setText("invoke onPrepared");
		startBtn.setEnabled(true);
	}

}

最后要在AndroidManifest.xml中加入Internet权限:

<uses-permission android:name="android.permission.INTERNET" />

git clone https://github.com/lnmcc/NetAudioPlayerExample.git

Android 音乐文件搜索和播放

main_activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/returnBtn"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="return" />

    <!-- 如果在代码中需要使用simple_list_item布局,那么这里的id必须为list -->

    <ListView
        android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Main_activity.java

public class MainActivity extends ListActivity implements LoaderCallbacks<Cursor> {
	
	//设置俩种选项状态:选择专辑或者选择歌曲
	public static int STATE_SELECT_ALBUM = 0;
	public static int STATE_SELECT_SONG = 1;
	//默认当前状态为选择专辑
	int currentState = STATE_SELECT_ALBUM;
	//查询专辑
	static final String[] AlbumColumns = {
		MediaStore.Audio.Albums._ID,
		MediaStore.Audio.Albums.ALBUM,
	};
	//查询歌曲
	static final String[] songColumns = {
		MediaStore.Audio.Media.DATA,
		MediaStore.Audio.Media._ID,
		MediaStore.Audio.Media.TITLE,
		MediaStore.Audio.Media.DISPLAY_NAME,
		MediaStore.Audio.Media.MIME_TYPE,
	};
	
	Cursor cursor;
	SimpleCursorAdapter mAdapter;
	Button returnBtn;
	MediaPlayer mediaPlayer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		returnBtn = (Button)findViewById(R.id.returnBtn);
		returnBtn.setOnClickListener(new View.OnClickListener() {
			//处理返回上级目录
			@Override
			public void onClick(View v) {
				if(currentState == STATE_SELECT_ALBUM) {
					//do nothing
				} else if(currentState == STATE_SELECT_SONG) {
					QueryAlbum();
					currentState = STATE_SELECT_ALBUM;
				}
			}
		});
		
	    //getLoaderManager().initLoader(0, null, this);
		QueryAlbum();
	}
	
	private void QueryAlbum() {
		
		//显示专辑查询结果
		String[] displayFields = new String[] {MediaStore.Audio.Albums.ALBUM};
		int[] displayViews = new int[] {android.R.id.text1};
		
	    mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, displayFields, displayViews, 0);
	    Bundle b = new Bundle();
	    b.putInt("state", STATE_SELECT_ALBUM);
	    getLoaderManager().restartLoader(0, b, this);
	    setListAdapter(mAdapter);
	}

	@Override
	public Loader<Cursor> onCreateLoader(int id, Bundle args) {
		
		Loader<Cursor> loader = null;
		if(args.getInt("state") == STATE_SELECT_ALBUM) {
			loader =  new CursorLoader(this, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, AlbumColumns, null, null, null);
		} else if(args.getInt("state") == STATE_SELECT_SONG) {
			String where = args.getString("where");
			String whereVal[] = args.getStringArray("whereVal");
			String orderBy = args.getString("orderBy");
			loader =  new CursorLoader(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songColumns, where, whereVal, orderBy);
		}
		return loader;
	}
	
	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
		cursor = data;
		mAdapter.swapCursor(data);
	}
	
	@Override
	public void onLoaderReset(Loader<Cursor> loader) {
		mAdapter.swapCursor(null);
	}
	
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		
		if(currentState == STATE_SELECT_ALBUM) {
			
			if(cursor.moveToPosition(position)) {
				String where = MediaStore.Audio.Media.ALBUM + "=?";
				String whereVal[] = {cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM))};
				String orderBy = MediaStore.Audio.Media.TITLE;
				String[] displayFileds = {MediaStore.Audio.Media.DISPLAY_NAME};
				int[] displayViews = new int[] {android.R.id.text1};
				
				mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, displayFileds, displayViews, 0);
				Bundle b = new Bundle();
				b.putInt("state", STATE_SELECT_SONG);
				b.putString("where", where);
				b.putStringArray("whereVal", whereVal);
				b.putString("orderBy", orderBy);
				getLoaderManager().restartLoader(0, b, this);
				setListAdapter(mAdapter);
				//进入专辑后,下一次选择模式一定是选择歌曲
				currentState = STATE_SELECT_SONG;
			}
		} else if(currentState == STATE_SELECT_SONG) {
			
			if(cursor.moveToPosition(position)) {
				int fileColumn = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
				int mimeTypeColumn = cursor.getColumnIndex(MediaStore.Audio.Media.MIME_TYPE);
				String audioFilePath = cursor.getString(fileColumn);
				String mimeType = cursor.getString(mimeTypeColumn);
				File audioFile = new File(audioFilePath);
				
				//打开下面3行可以使用外部播放器播放音频
				//Intent i = new Intent(android.content.Intent.ACTION_VIEW);
				//i.setDataAndType(Uri.fromFile(audioFile), mimeType);
				//startActivity(i);
				
				//使用MediaPlayer播放音频
				if(null != mediaPlayer && mediaPlayer.isPlaying()) {
					mediaPlayer.stop();
					mediaPlayer.release();
				}
				mediaPlayer = MediaPlayer.create(this, Uri.fromFile(audioFile));
				mediaPlayer.start();
			}
		}
	}

	@Override
	protected void onStop() {
		super.onStop();
		if(null != mediaPlayer) {
			mediaPlayer.start();
			mediaPlayer.release();
		}
	}
}

git clone https://github.com/lnmcc/AudioBrowserAndPlayExample.git