• Advertisement


  • Content count

  • Joined

  • Last visited

Community Reputation

864 Good

About Sharlin

  • Rank
    Advanced Member
  1. New Deus Ex 3 Trailer Out, Wins the Internets

    A representative of Eidos has claimed that almost everything we see in the trailer except animation and rendering is the dev team's own handiwork -- the script, overall atmosphere, visual style, assets. So some cautious optimism may be warranted. But we'll get a look at the gameplay soon enough.
  2. A new pre-E3 trailer for Deus Ex: Human Revolution has been making rounds around the intertubes for the past few days, and to describe the general response as enthusiastic would be the understatement of the year. Awesome sauce has been liberally applied. Link to 720p goodness Here's to hope the actual game lives up to even half the promise...
  3. FWIW, the problem is undecidable in the general case: Rice's Theorem states that for any "non-trivial" property, there does not exist an algorithm that decides whether an arbitrary program has that property.
  4. [C++] 8 booleans vs. 1 char

    Um, the latest stable release of GCC is 4.4.0. I compiled your code with an old GCC 4.0.3 and with -O3 it completely optimized away all the bitset operations from the generated assembly. Modifying the code so that the computations can't be statically calculated, and their results are actually used, yielded assembly output indistinguishable from equivalent code written by hand.
  5. Thanks for the comments! std::unique_lock already has RAII (with move) semantics (for example, notice that the producer doesn't manually release the lock), so the code should be exception safe as is. The manual locking/unlocking in the consumer was mostly to demonstrate that it's possible if such flexibility is required. But as you all pointed out, freeing the user from the burden of explicitly holding the lock is a logical next step in improving the abstraction. I didn't have any better things to do, so I wrote an improved version, available here :)
  6. I've been toying with GCC 4.4 and its experimental C++0x mode and the new threading library in particular. I ended up with a simple example of the producer/consumer pattern and decided to share it here. Comments and critique welcome :) There are a couple of places that could be made less UB prone with a little refactoring; that is left as an exercise to the reader. EDIT: Also available here. // // A simple implementation of the well-known Producer/Consumer pattern // demonstrating the C++0x thread library and certain other new features. // // Written by Johannes Dahlström // This file is in the public domain. // #include <thread> #include <condition_variable> #include <queue> #include <chrono> #include <iostream> #include <cstdlib> #include <functional> using namespace std; // Represents a pool of data with thread-safe producer/consumer semantics class work_pool { public: typedef unique_lock<std::mutex> lock_type; work_pool(int max_size) : max_size(max_size) { } // Acquires a lock on the pool and returns it // A thread MUST hold a lock on the pool // before calling ANY other member functions. lock_type lock() { return lock_type(mutex); } // Pushes a datum to the work pool void produce(int i) { queue.push(i); } // Pops a datum from the work pool int consume() { int res = queue.front(); queue.pop(); return res; } // Returns whether the pool is full bool is_full() { return queue.size() >= max_size; } // Returns whether the pool has data bool has_data() { return !queue.empty(); } // Returns the number of items in the pool int size() { return queue.size(); } // Atomically releases lock, blocks until there // is new data in the pool, then reacquires the lock // lock MUST hold the same mutex as the one returned by lock() void wait(lock_type& lock) { // Wait until being notified AND there is data in the pool cvar.wait(lock, bind(&work_pool::has_data, this)); } // Notifies the consumer threads waiting on this pool void notify() { cvar.notify_all(); } private: int max_size; std::queue<int> queue; std::condition_variable cvar; std::mutex mutex; }; // Produces data into the given work pool. void produce(int id, work_pool& pool) { static int i = 0; while(true) { // Simulate some heavy work being done this_thread::sleep_for(chrono::milliseconds(rand() % 3000)); // Acquire lock on the work pool work_pool::lock_type lock(pool.lock()); // Push data to pool if not full if(!pool.is_full()) { pool.produce(i++); cerr << " producer " << id << ": " << i << " size=" << pool.size() << '\n'; } // Notify consumers pool.notify(); } } // Consumes data from the given work pool. void consume(int id, work_pool& pool) { // Acquire lock on the work pool work_pool::lock_type lock(pool.lock()); while(1) { // Release lock, wait for new data pool.wait(lock); // wait reacquires the lock before returning // Consume data from pool int i = pool.consume(); cerr << " consumer " << id << ": " << i << " size=" << pool.size() << "\n\n"; // rand is not thread-safe so call it before releasing the lock int delay = rand() % 3000; // Release lock on pool, simulate work being done lock.unlock(); this_thread::sleep_for(chrono::milliseconds(delay)); lock.lock(); } } int main() { srand(time(0)); work_pool pool(10); // Spawn producer and consumer threads vector<thread> producers, consumers; for(int i = 0; i < 4; ++i) { // emplace_back constructs the object in-place using perfect forwarding // equivalent to push_back(thread(...)) but avoids a potential copy/move consumers.emplace_back(consume, i, ref(pool)); producers.emplace_back(produce, i, ref(pool)); } while(true); }
  7. Note that the Standard Library offers ready-made comparison function objects: std::less, std::less_equal, std::greater, std::greater_equal, std::equal_to, and std::not_equal_to :)
  8. I would've thought that (s.Base::*fptr)(); had worked, but alas, no :/
  9. Best/Classic "one-liner" from hit titles...

    I'm surprised these aren't already here: Quote:Deus Ex: Anna Navarre: Don't tell me you're going to wear those sunglasses during a night operation. JC Denton: My vision is augmented. Walton Simons: You take another step forward and here I am again, like your own reflection in a hall of mirrors. JC Denton: That makes me one ugly son of a bitch. Bob Page: Soon, I will become pure energy. I will burn like the brightest star. JC Denton: You're gonna burn, all right. Dr. Jaime Reyes: JC! You escaped? Is that what the lockdown's about? JC Denton: I forgot to give Manderley my resignation. JC Denton: You've got ten seconds to beat it before I add you to the list of NSF casualties. JC Denton: Bravery is not a function of firepower.
  10. In the current language, function template parameters can't be deduced from default arguments; neither can function template parameters have default values, unlike class template parameters. This is an inconvenience that will be fixed in the next standard, but in the meantime, an acceptable workaround is to write an overload that forwards to the "full" version of the template. Anyway, your use of __FILE__ and __LINE__ is problematic: because they are expanded by the preprocessor, they will always expand to the same values — specifically, the file and line where error is declared! If you want to output the file and line of the call site, you'll have to resort to a macro: #define ERROR(lvl, err, arg) error(lvl, err, arg, __FILE__, __LINE__)Unfortunately, macros can't have default arguments, neither can they be overloaded... Also, error/warning/log messages should probably go to std::cerr or std::clog. They both write to standard error instead of standard output (so that, for instance, error messages can be redirected to a file independent of normal output); additionally, std::cerr does unbuffered output so that everything is always written even if the program crashes.
  11. A naive bitwise approach like that isn't going to work except in the simplest of cases, and it's not guaranteed to work even then. It's simply bad code. Real-world serialization is a nontrivial problem with no simple solutions in the general case. A couple links you should definitely familiarize yourself with: C++ FAQ Lite: Serialization Boost Serialization library
  12. You have to notify the other thread somehow (via a message queue, synchronized global variable, etc.) that it should stop, then wait for it to exit with thread::join(). Boost.Threads doesn't offer a way to do a "hard" asynchronous kill precisely because it wouldn't be safe and would probably leak resources.
  13. Hmm... that's the "canonical" form of a factorial function which works in *any* language that supports recursion. Let's unwind the recursive call and see what it looks like. For every f(k), we're substituting k*f(k-1), as per the definition: f(n) = n * f(n-1) = n * ( (n-1) * f((n-1)-1) ) = n * ( (n-1) * ( (n-1-1) * f((n-1-1)-1) ) ) = n * ( (n-1) * ( (n-1-1) * ( (n-1-1-1) * f((n-1-1-1)-1) ) ) ) = ... = n * (n-1) * (n-1-1) * ... * f(n-(n-1)) = n * (n-1) * (n-1-1) * ... * 1 = n!
  14. Of course, it's often possible to pack *multiple* values into a single integer — see, for instance, std::vector<bool> which truly uses just a single bit for each bool stored, plus a bit of padding at the end of the vector.
  15. I suck at Starcraft

    Quote:qdb.us ATH0: I don't know why the Korean guys at school love Steve so much. ATH0: He doesn't look too Korean. Batman: He told me. Batman: Basically, he beat them at StarCraft and became their king.
  • Advertisement