Perşembe, Ağustos 20, 2009

Ubuntu Intrepid Ibex(8.10) üzerinde Rails geliştirme ortamı kurulumu

İlk olarak ruby paketleri ve sqlite3 paketi yüklenmelidir.
sudo aptitude install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby sqlite3 libsqlite3-ruby1.8

Yüklenen bu programlar için /usr/bin içerisine symlinkler oluşturulur.
sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby
sudo ln -s /usr/bin/ri1.8 /usr/bin/ri
sudo ln -s /usr/bin/rdoc1.8 /usr/bin/rdoc
sudo ln -s /usr/bin/irb1.8 /usr/bin/irb

Ruby kurulumu tamamlandığına göre kontrol edebiliriz.
ruby –v
...
ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux]

Rubygems ruby kod kitaplıklarının kurulması için kullanılan bir araçtır. Rubygems kurulumu paketler kullanılarak da yapılabilir fakat son sürümün kurulması önemli olduğu için kaynak koddan kurulum tercih edilmelidir. Son sürüm http://rubyforge.org/projects/rubygems/ sayfasından öğrenilebilir. Burada son sürüm 1.3.5 idi.
wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.5.tgz
tar xzvf rubygems-1.3.5.tgz
cd rubygems-1.3.5
sudo ruby setup.rb
...

Rubygems kurulumu aşağıdaki mesajla tamamlanır.
RubyGems installed the following executables:
/usr/bin/gem1.8

If `gem` was installed by a previous RubyGems installation, you may need
to remove it by hand.

Son olarak bir symlink oluşturulur ve Rubygems kurulumu aşağıdaki gibi kontrol edilebilir.
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
gem –v
...
1.3.5

Rubygems ile kurulan ‘gem’lerin son sürümde oldukları sık sık
sudo gem update --system

ile kontrol edilmelidir. Rubygems kurulumunu tamamladığımıza göre Rails kurulumuna geçebiliriz.
sudo gem install rails

Son olarak her şeyi kontrol etmek için
sudo gem list

çıktısı aşağıdaki gibi olmalıdır.
*** LOCAL GEMS ***

actionmailer (2.2.2)
actionpack (2.2.2)
activerecord (2.2.2)
activeresource (2.2.2)
activesupport (2.2.2)
rails (2.2.2)
rake (0.8.3)

Sqlite3 modülünün çalıştığını kontrol edelim.
irb
irb(main):001:0> require 'sqlite3'
=> true
irb(main):002:0> exit

RoR kurulumunu tamamladık. Ubuntu üzerinde geliştirme için ayrıca subversion ve git sürüm kontrol sistemlerine ihtiyaç duyulacaktır. Git zaten kurulu olmalı subversion için de
sudo aptitude install subversion 

paketi yüklenmelidir.

Cuma, Temmuz 10, 2009

Git ile bir Rails uygulamasının kontrol edilmesi

Git versiyon kontrol sisteminin diğerlerinden farklı olduğu noktalardan birisi de kodların barındığı repository'nin merkezi olması gerekmemesidir. Bir git repositorysi yerel olarak oluşturulur ve yapılan değişiklikler gerektiğinde farklı bir serverda bulunan merkezi bir repository'ye 'push' edilerek gönderilir. Burada git versiyon kontrol sisteminin incelenmesi için özel olarak bir rails uygulamasının kurulması üzerinde durulmuştur.
İlk olarak todo isimli yeni bir rails uygulaması oluşturulmuştur.

hamdi@hamdi-laptop:~/railsProjects$ rails todo
create
create app/controllers
.... sadelik için detaylar atlandı.
create log/test.log

Yeni bir git repository oluşturmak için istenilen dizin içerisinde "git init" komutu çalıştırılır:

hamdi@hamdi-laptop:~/railsProjects$ cd todo
hamdi@hamdi-laptop:~/railsProjects/todo$ git init
Initialized empty Git repository in /home/hamdi/railsProjects/todo/.git

Rails uygulamasının içerisinde git tarafından kontrol edilmesi istenmeyen dosyaları belirtmek için bu dizinde bir ".gitignore" dosyası oluşturulmalıdır.
.gitignore içerisinde:

log/*.log
tmp/**/*
db/*.sqlite3
config/database.yml

Git repository'sinin şu anki durumunu görmek için:

hamdi@hamdi-laptop:~/railsProjects/todo$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# .gitignore
# README
# Rakefile
# app/
# config/
# doc/
# public/
# script/
# test/
nothing added to commit but untracked files present (use "git add" to track)

Yukarıda görüldüğü gibi repository'de henüz takip edilen hiçbir dosya yok. Fakat takip edilmeyenler listesinde bazı dizinler boş olduğu için listelenmemekteler. Dizinler boş olsa da kontrol edilmesini isteyebiliriz. Bunu çözmek için bu dizinler içerisinde boş bir dosya oluşturulabilir. touch komutu ile boş .gitignore dosyaları aşağıdaki gibi oluşturulabilir.

hamdi@hamdi-laptop:~/railsProjects/todo$ touch log/.gitignore tmp/.gitignore vendor/.gitignore

Şimdi git status ile bakılırsa boş dizinlerin de konrol edilmediği listelenecektir.

hamdi@hamdi-laptop:~/railsProjects/todo$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# .gitignore
# README
# Rakefile
# app/
# config/
# doc/
# log/
# public/
# script/
# test/
# tmp/
# vendor/
nothing added to commit but untracked files present (use "git add" to track)

Artık projenin kontrol edilmesi için dosyaları ekleyebiliriz. Git'de eklenmek istenen dosya veya değişiklikler add komutu ile önce "staging index"e eklenir. Daha sonra "commit" ile bu değişiklikler "working copy" haline gelir.

hamdi@hamdi-laptop:~/railsProjects/todo$ git add .

Şimdi kontrol durumuna bakılırsa:

hamdi@hamdi-laptop:~/railsProjects/todo$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: .gitignore
# new file: README
# new file: Rakefile
... atlandı ...
# new file: script/server
# new file: test/performance/browsing_test.rb
# new file: test/test_helper.rb
# new file: tmp/.gitignore
# new file: vendor/.gitignore
#

hamdi@hamdi-laptop:~/railsProjects/todo$ git commit -a -m "ilk ekleme"
Created initial commit 55d5e33: ilk ekleme
41 files changed, 8434 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
create mode 100644 README
... atlandı ...
create mode 100644 test/performance/browsing_test.rb
create mode 100644 test/test_helper.rb
create mode 100644 tmp/.gitignore
create mode 100644 vendor/.gitignore

Uygulamaya bir model eklenmiş olsun:

hamdi@hamdi-laptop:~/railsProjects/todo$ ./script/generate model task name:string
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/task.rb
create test/unit/task_test.rb
create test/fixtures/tasks.yml
create db/migrate
create db/migrate/20090710132706_create_tasks.rb
hamdi@hamdi-laptop:~/railsProjects/todo$ rake db:migrate
(in /home/hamdi/railsProjects/todo)
== CreateTasks: migrating ====================================================
-- create_table(:tasks)
-> 0.0014s
== CreateTasks: migrated (0.0016s) ===========================================

Son değişiklikleri eklemek için tekrar yeni dosyalar add ile "staging index"e sonra da tüm değişiklikler commit ile eklenir.

hamdi@hamdi-laptop:~/railsProjects/todo$ git add .
hamdi@hamdi-laptop:~/railsProjects/todo$ git commit -a -m "task modeli eklendi."
Created commit b3d0cd9: task modeli eklendi.
5 files changed, 50 insertions(+), 0 deletions(-)
create mode 100644 app/models/task.rb
create mode 100644 db/migrate/20090710132706_create_tasks.rb
create mode 100644 db/schema.rb
create mode 100644 test/fixtures/tasks.yml
create mode 100644 test/unit/task_test.rb

Henüz add komutu ile "staging index"e eklenmemiş değişiklikleri geri almak için git checkout filename komutu kullanılır. Eğer değişiklikler "staging index"e eklenmişse, "staging index"i en son commit işlemine geri almak için git reset HEAD somefile.txt komutu kullanılır. HEAD son commiti belirtmektedir. /TODO: diğer commitler/ Eğer komut sadece git reset HEAD şeklinde kullanılırsa sadece bir dosya değil tüm dosyalar geri alınır. Bundan sonra git checkout filename ilegeri dönülebilir.

Cuma, Nisan 24, 2009

Django Dersleri 1

Django'yu bilen bilir, iyidir hoştur da her 'taze' teknoloji gibi Türkçe doküman sıkıntısı vardır. Eh bende çorba tuzum olsun diyerek Django Tutorial'ı çevirmeye koyuldum. Yanlız şunu belirtmeliyim ki ciddi olarak programlama ile uğraşmak isteyenlerin zahmet edip İngilizce öğrenmesi gerektiğini düşünüyorum. Fakat bu kesinlikle ben biliyorum, bilmeyenlerden üstünüm iması değil. Demek istediğim nasıl ki bir tarihçi Osmanlıca bilmeden, yazıtları okuyamadan ben Osmanlı tarihçisiyim diyince biraz garip oluyorsa; burada da durum aynı bence. Neyse geçelim Django'ya. Burada python, django ve veritabanınızı kurduğunuzu varsayıyorum. henüz kurmadıysanız buyrun. Ayrıca linux kullandığınızı varsayıyorum.

Proje yaratma:

İlk yapacağımız bir django projesi için gerekli temel ayarları yapmak ve temel proje kodunu otomatik oluşturmak bunun için projeyi saklayacağımız dizine geçip:
django-admin.py startproject myproject

diyoruz ve mysite dizini altında ilk django projemiz oluşturulmuş oluyor. Bakalım ne yapmış sitem dizini içerisinde
mysite/
__init__.py
manage.py
settings.py
urls.py

Bunlar ne iş yapar diyorsanız:
  • __init__.py: Python'a bu dizinin bir python paketi olduğunu söyleyen boş bir dosya. (Daha fazla bilgi için resmi python dokümantasyonunda paketler kısmına bakabilirsiniz. )
  • manage.py: Django projenizle ilgili birçok işi yapmak için kullanacağımız komut-satırı aracı. Buna daha sonra geleceğiz. Detay için django-admin.py and manage.py.
  • settings.py: Bu Django projesi için gerekli ayarları yaptığımız dosya. Daha fazla bilgi için dokümantasyonda Django settings'e bakılabilir.
  • urls.py: Bu Django projesi için URL bildirimleri. Hangi URL ne iş yapacak hangi sayfaya gidecek şeklinde düşüneblirsiniz. Orjinal dokümantasyon için: URL dispatcher.
Geliştirme Server'ı

Buraya kadar sorun var mı görmek için mysite dizini içerisinde
python manage.py runserver

komutu ile geliştirme serverını başlatabilirsiniz.
Validating models...
0 errors found.

Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Çıktısını gördüyseniz bir sorun yok demektir. Tarayıcınızda http://127.0.0.1:8000/ 'e giderseniz, bir hoşgeldin yazısını görebilirsiniz.
Portu değiştirmek için
python manage.py runserver 8080
ile çalıştırabilirsiniz. Eğer yerel ağınızdaki bilgisayarların erişebilmesini isterseniz
python manage.py 0.0.0.0:8000
ile başlatabilirsiniz. Fakat unutmayın bu server sadece geliştirme amaçlı. Sitenizi gerçek kullanıma açmak için 'gerçek' bir server kullanmalısınız. Bu konuya daha sonra geliriz.
Veritabanı ayarları
settings.py açın ve aşağıdaki ayarları ihtiyacınıza göre değiştirin. Bir çok veritabanı kullanabilmemize rağmen basitlik açısından önce sqlite kullanmanızı öneririm.
  • DATABASE_ENGINE -- 'postgresql_psycopg2', 'mysql' veya 'sqlite3'. Diğer seçenekler de mevcut.

  • DATABASE_NAME -- Veritabanı ismi. SQLite için bilgisayarınızda tutulacak dosyanın ismi. Dosyanın tam yolu olmalı. Aynı dizinde olması için 'dev.db' gibi bir isim yeterli.

  • DATABASE_USER -- Veritabanı kullanıcı ismi (SQLite için kullanılmıyor).

  • DATABASE_PASSWORD -- Veritabanı şifre (SQLite için kullanılmıyor).

  • DATABASE_HOST -- Veritabanınızın tutulduğu bilgisayar. Aynı fiziksel host için boş bırakın (SQLite için kullanılmıyor).

Hala settings.py'de iken INSTALLED_APPS kısmına bir göz atın buraya kullanacağımız uygulamaları ekleyeceğiz. İlk gelenler sıklıkla(hemen herzaman) kullanılanlar. O yüzden değişiklik yapmanıza şimdilik gerek yok.

Veritabanı ayarlarını yaptığımıza göre kullanacağımız uygulamaların ihtiyacı olan veritabanı tablolarını oluşturabiliriz.
python manage.py syncdb

Her uygulama için oluşturulan tabloları listeleyecek ve bir superuser hesabı oluşturmanızı isteyecek. Bu aşamada oluşturun çünkü admin menüsü kısmına geldiğimizde lazım olacak.

Model Oluşturmak

Artık 'proje'nin ayarları tamam olduğuna göre işimiz bakabiliriz. Sıradaki işimiz bir uygulama oluşturmak olacak. Uygulamaların asıl amacı PYTHONPATH'iniz içinde bir package oluşturmak ve aynı kodu başka bir projede tekrar kullanabilmenizi sağlamaktır. Fakat şimdilik bir oy verme uygulaması yapacağız ve yazdığımız kod projeye bağımlı olacak. Tamamen tekrar kullanılabilir bir uygulama yazmak bu yazının kapsamı dışında. Bu uygulamaya (orjinal dökümanla tutarlı olması açısında)polls ismini vereceğim. İsterseniz siz başka birşey kullanabilirsiniz.
python manage.py startapp polls

Oluşturulacak polls dizini:
polls/
__init__.py
models.py
views.py

Uygulamamız hazır modellerimize geçebiliriz. Modeller uygulamamızın vertabanı kısmında tutacağımız verileri tutacağımız sınıflar olacak. Yani yapmaya başladığımız ilk iş olmasının iyi bir sebebi var. Geri kalan tüm işlevsellik bir şekilde bunlarla ilişkili olacak.
polls/models.py dosyasını aşağıdaki kodla değiştirin.
from django.db import models

class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')

class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
votes = models.IntegerField()


Yukarıdaki kod dikkatle incelediğinde rahatlıkla anlaşılabilir. Her model django.db.models.Model sınıfından türetilen bir sınıfla temsil edilir. Bir model sınıfının sahip olduğu her üye değişken bir veritabanı alanını(veritabanı tablosunda sütünu) temsil eder.

Veritabanı alanlarını tanımlamak için de Field sınıfından türetilmiş nesneleri kullanıyoruz. Örneğin bir karakter alanı için CharField ve tarihler için DateTimeField türünden nesneler kullanarak her alanın veri tipini belirliyoruz.

Alan değişkenlerine verilen isimler (yani question veya pub_date gibi) normal python değişkenleri gibi isimlendirilir ve kodumuz içerisinde veritabanının sütünlarını belirtmek için kullanılır.

Her Field opsiyonel olarak alanın tanımını içeren bir string alır. Alanları verilen bu tanım kodun anlaşılmasına yardım etmesinin dışında Django tarafından oluşturulan admin menüsünde de kullanılır. Bu isim belirtilmediği takdirde Django değişken ismini kullanacaktır.Bu örnekte sadece Poll.pub_date alanı için tanım belirttik, diğer alanlar için değişken ismi yeterli görülmüştür.

Bazı Field sınıfları için tanımlanması zorunlu özellikler vardır. Örneğin CharField, max_length ile maksimum uzunluğun belirtilmesini gerektirir. Bu değer sadece veritabanı şemasında değil ileride göreceğimiz gibi validasyonda da kullanılacaktır.

Son olarak tablolar arası ilişki için ForeignKey kulanıldığını söyleyelim. Yukarıdaki örnekte her bir Choice nesnesinin tek bir Poll nesnesine ait olduğu anlamına gelir. Django tüm yaygın veritabanı ilişkilerini destekler: çoktan bire, çoktan çoğa ve birden bire.

Modelleri Kullanmak
Bu küçük model kodumuz django'nun bize yardım etmesi için birçok bilgi içeriyor. Bu kod sayesinde django:

Bu uygulama için veritabanı şemamızı yaratabilir. (istediğimiz veritabanı yönetim sistemi için CREATE TABLE ifadelerini üretebilir).
Poll and Choice nesneleri için python içerisinden veri tabanına erişmemizi sağlayacak API'yı üretebilir.
Fakat ilk önce projemize uygulamamızı kullanmasını söylemeliyiz. ( Django uygulamaları "pluggable-takılabilir?" dir yani : Bir uygulamayı birden fazla projede kullanabilirsiniz, ve uygulamaları başkalarının kullanabilmesi için yayınlayabilirsiniz çünkü uygulamalar belirli bir django projesine veya kurulumuna bağlı değildir.)
settings.py dosyasını tekrar açın ve INSTALLED_APPS çoklusunun 'mysite.polls' değerini de içermesini sağlayın ki aşağıdaki gibi olsun:

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'mysite.polls'
)

Artık django mysite projesinin polls uygulamasını da içerdiğini biliyor. Başka bir django komutu yürütelim:
python manage.py sql polls

Aşağıdaki gibi bir çıktı almalısınız (polls uygulaması için CREATE TABLE SQL deyimleri):

BEGIN;
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
"choice" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
COMMIT;


Bu sql deyimlerinin yürütülmesi için:
python manage.py syncdb

komutunu tekrar çalıştırmalısınız. syncdb komutu settings.py'daki INSTALLED_APPS içinde belirtilen tüm uygulamalar için henüz yaratılmamış tabloları yaratır. Bu komutun tekrar çalıştırılması veri kaybına neden olmaz sadece yeni tablo yaratmak için kullanılır.

Api'ile oynamak

Gerçekten uygulama geliştirmeye başlamadan önce interaktif python kabuğunda Django veritabanı API'si ile oynamak eğitici olacaktır. Kabuğu başlatmak için:

python manage.py shell


komutunu kullanıyoruz. Sadece python ile başlatabileceğimiz kabuğun yerine bu komutu kullanarak iki işlemi elle yapmaktan kurtuluyoruz. Birincisi mysite'ı sys.path üzerine eklemek. Bu django'da sıklıkla kullanılan mysite.polls.models şeklinde erişimi sağlıyor. INSTALLED_APPS uygulama listesinde uygulamaları bu şekilde belirttiğimizi hatırlayın. İkincisi, DJANGO_SETTINGS_MODULE ortam değişkeninin projemizin settings.py dosyasını göstermesinin sağlanmasıdır. Eğer bu işlemleri kendiniz yaparsanız pekala standart kabuğu kullanabilirsiniz. Fakat shell komutu ile bu işlemleri farklı uygulamalar için her seferinde yapma derdinden kurtulmuş oluyoruz.

Aşağıdaki komutları deneyerek öğrenmeye devam edebilirsiniz:


>>> from mysite.polls.models import Poll, Choice # Import the model classes we just wrote.

# No polls are in the system yet.
>>> Poll.objects.all()
[]

# Create a new Poll.
>>> import datetime
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())

# Save the object into the database. You have to call save() explicitly.
>>> p.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> p.id
1

# Access database columns via Python attributes.
>>> p.question
"What's up?"
>>> p.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53)

# Change values by changing the attributes, then calling save().
>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
>>> p.save()

# objects.all() displays all the polls in the database.
>>> Poll.objects.all()
[]


Pazartesi, Eylül 08, 2008

Google AppEngine ile Ajax

Bir süredir Google AppEngine ile uğraşıyorum. Deneyimlerimi paylaşmak adına bir Ajax örneğini incelemek istedim.
main.py :
import cgi
import wsgiref.handlers
from google.appengine.ext import webapp

class AjaxPage(webapp.RequestHandler):
def get(self):
self.response.out.write("""
<html><head><title>Ajax Example</title>
<script language="Javascript">
var xr;
function xmlhttpPost(strURL,strQuery)
{
if (window.XMLHttpRequest) // Mozilla/Safari
{ xr = new XMLHttpRequest(); }
else if (window.ActiveXObject) // IE
{ xr = new ActiveXObject("Microsoft.XMLHTTP"); }
xr.open('POST', strURL, true);
xr.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
xr.onreadystatechange = function()
{ if (xr.readyState == 4)
{ xrback(xr.responseText);} }
xr.send(strQuery);
}

function xrback(str)
{
eval(str);
document.getElementById("result").innerHTML
= j.a;
}

</script>
</head>
<body onload="javascript:xmlhttpPost('/ajax','r=a')">
<p id="result">Loading...</p>
</body></html>""")

class AjaxCall(webapp.RequestHandler):
def post(self):
r = self.request.get('r')
self.response.out.write(
"var j = { '"+r+"' : 'Hello World'}; ")

def main():
application = webapp.WSGIApplication( [
('/', AjaxPage),
('/ajax', AjaxCall),
], debug=True)
wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
main()

Burada ilk olarak her ajax uygulamasında ilk ihtiyacımız olan XMLHttpRequest nesnesini '/' urlsine bağladığımız AjaxPage yaratıyor. body onload'da Ajax çağrısını /ajax'a gönderiyor. Bu çağrıya json ile karşılık veriyoruz. Böylece "result" idli elemana "a" isimli değişkenin değeri olan o meşhur "Hello World" katarını aktarabiliyoruz. Sanırım daha karmaşık uygulamalar için bu bir temel oluşturabilir.

Cumartesi, Nisan 26, 2008

Boost ile multi threading

C++ ile multithreaded (çok iplikli?) program yazmak istediğimizde malesef bunun standart c++ ile mümkün olmadığını görüyouz. Akla gelen ilk alternatifler ise işletim sistemine bağlı kitaplıklar. Burada Boost.Threads'in ise ayrı bir yeri var. Standart olmasa da buna aday olması, taşınabilirliği, yapımında birçok C++ uzmanının görüşlerinin alınmış olması ve tamamem C++ tabanlı (diğer birçok kitaplık c tabanlı) olması Boost.Threads'in avantajları. boost.org'dan daha fazla bilgi alabilir ve son sürümünü indirebilirsiniz. Burada kısaca Boost.Threads'in kullanımından bahsedeceğim.

boost::thread sınıfı bir threadi temsil ediyor. Varsayılan kurucu (default constructor) yürütülen threadi temsil eden bir nesne oluşturur. Diğer bir kurucu da parametre olarak, parametre almayan ve bir değer döndürmeyen bir function object (fonksiyon nesnesi) alır. Yeni bir thread oluşturarak bu function object'i çağırır. İlk bakışta klasik C tarzı void işaretçi alan fonksiyona göre daha uğraştırıcı bir yöntem gibi gözükse de Boost.Bind gibi fonksiyonel kitaplıklarla çok rahat kullanılabiliyor. Yaratılan threadle yapılabilecekler '==' , '!=' operatörleri ve boost::thread::join ile bir threadin sonlanmasını beklemek. Aşağıdaki örnekte sadece bir "hello world" yazan thread oluşturulup sonlanması bekleniyor.
#include <boost/thread/thread.hpp>
#include <iostream>

void hello()
{
std::cout <<
"Hello world, I'm a thread!"
<< std::endl;
}

int main(int argc, char* argv[])
{
boost::thread thrd(&hello);
thrd.join();
return 0;
}

Yukarıdaki fonksiyona bir veri aktarmak isteseydik yapmamız gereken bir function object yazmak olacaktı. Her thread oluşturduğumuzda bu gerçekten can sıkıcı olurdu. Bunun yerine aşağıdaki örnekte Boost.Bind ile bu işi nasıl yapabileceğimiz görülüyor. Ayrıca aşağıdaki kodda en basit hali ile mutex kullanımı görülüyor. Mutexlerin diğer çeşitleri ile ilgili detaylara girmeyeceğim. Zaten kullanım olarak çok farklı değiller. Burada tanımlanan mutex boost::mutex::scoped_lock ile kurucuda kilitleniyor ve yıkıcıda da kilit kaldırılmış oluyor. Böylece paylaşılan kaynak olan std::cout 'a aynı anda tek bir threadin erişebilmesi sağlanıyor.
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>

boost::mutex io_mutex;

void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}

int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}

Birden fazla thread yaratılacağı zaman işe yarayabilecek bir şey de boost::thread_group sınıfı. Bu sınıf sayesinde birden fazla thread üzerinde beklemek için tek tek belirtmeye gerek kalmıyor.
#include <boost/thread/thread.hpp>
#include <iostream>

void count(int id)
{
std::cout << std::endl;
}

int main(int argc, char* argv[])
{
boost::thread_group thrds;
for(int i=0; i<5; i++)
thrds.create_thread( boost::bind(&count, i) );

thrds.join_all();
return 0;
}

Salı, Mart 25, 2008

Peg Solitaire

Geçenlerde C# öğrenmek adına XNA Game Studio ile ilgilenmeye karar vermiştim. Küçük bir oyun yapmak istiyordum. Fikir ararken Yapay zeka dersinin ödevi olarak Peg solitaire için çözüm arayan bir program yazmamız istendi. O arada oyunu kağıt üstünde çözme denemelerim başarısızlıkla sonuçlanınca bu program çıktı ortaya. İlgilenenler için kaynak kodlar ve kurulum paketi burada.

Not: XNA ile oyun geliştirmiş olanlar yani .net Framework ve XNA Framework Redistributable ve DirectX 9.0c bilgisayarında kurulu olanlar için bu çalıştırılabilir sürüm olarak yeterli.

Burada nokta niyetine anca bu gider.

Cumartesi, Kasım 10, 2007

Virtual PC 2007 ile Ubuntu 7.10(Gutsy Gibbon) kurulumu

Ubuntu'ya aslında biraz kızgınım. Yaklaşık 6-7 aydır kurulu olan edgy, en uzun süre bana sorun çıkarmayan linux versiyonu olarak Ubuntuya kalbimde ayrı bir yer kazandırmıştı. Taki tam da linuxa ihtiyacım olan, system programming ödevini yapacağım zaman standart güncelleştirmelerini yaptıktan sonra ilginç bir şekilde grub'un boot listesinden Windowsu silmesi, ubuntunun ise boot sırasında bir hata vererek açılmaması gerçekten sinir bozucu oldu. Ödevi knoppix ile hallettikten sonra hangi linuxu kurayım diye araştırırken Ubuntu 7.10'un geçenlerde çıkmış olduğunu gördüm ve bir şans vereyim dedim. Fakat bu sefer risk almayıp Virtual PC 2007 kurdum. Tahmin ettiğim gibi ubuntuyla pek iyi anlaşamadılar ama şanslıydım ki aynı sorunları yaşayan birileri çözümü bloglarında yazmışlardı. Ben de çözümü Türkçe olarak burada belirtmek istedim.
Virtual PC kurulumundan bahsetmek gerekirse 30mb alan istiyor ve ücretsiz indirilebiliyor. Kurulumda bir sorun yok tabi:) Daha sonra New Virtual Machine sihirbazı ile yeni bir makine yaratıyoruz. Gerekli sabit disk miktarı ve en az 256mb ram verdikten sonra makine çalışıyor. CD menüsünden Capture ISO Image ile indirdiğimiz dosyanın yüklenmesini sağlıyoruz. Sorun mouse'un çalışmaması olarak karşımıza çıkıyor ve kernelin virtual pc ile uyumsuzluğundan kaynaklanıyormuş. Şuradaki çözümü uyguladım. Giriş ekranında "Start Ubuntu in Safe Graphics Mode" seçeneği üzerindeyken F6 ya basarak seçenekler satırının gözükmesini sağlayın ve
"...quiet splash --" dan sonra bir boşluk ve ardından "i8042.noloop" ekleyin. Bu live mode esnasında mouse kullanmamızı sağlayacak. Daha sonra kurulumu tamamlayın(epey zaman alıyor benim dizüstüde yaklaşık 1 saat sürdü). Yeni işletim sistemini açmak için yeniden başlatın. Bu arada CD'nin isosunu ayırmayı unutmayın. Grub başlarken ESC'ye basarak seçeneklerin görünmesini sağlayın. İlk satırı düzenlemek için 'e'ye basın, kernel ile başlayan satırda iken tekrar 'e' ye basarak sonuna i8042.noloop ekleyin. Enter'la önceki menüye dönün ve yine kernel satırı seçiliyken 'b'ye basarak sistemin başlamasını sağlayın. Login olduktan sonra bu sorunu tam olarak çözmek için konsolda sudo gedit /boot/grub/menu.lst konutunu çalıştırın. Dosyanın sonlarında(recovery mode kısmına değil) kernel ile başlayan satırın sonuna i8042.noloop ekleyerek kaydedin. Artık yeniden başlattığınızda mouse çalışıyor olacaktır.
Bir süre bu Virtual PC ile idare ederim heralde ama fırsat bulunca tam yükleme yapmak gerekiyor en azından daha hızlı çalışabilmek için.